diff --git a/src/main/java/Presenter/Algorithms/Algorithm.java b/src/main/java/Presenter/Algorithms/Algorithm.java index 80eb110..9a1cee3 100644 --- a/src/main/java/Presenter/Algorithms/Algorithm.java +++ b/src/main/java/Presenter/Algorithms/Algorithm.java @@ -9,5 +9,6 @@ package Presenter.Algorithms; */ public interface Algorithm { - + void run(); + void getResult(); } diff --git a/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java b/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java index 73e0182..6df4dd5 100644 --- a/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java +++ b/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java @@ -65,17 +65,14 @@ public class LeastMedianOfSquaresEstimator extends Observable implements Algorit public void run() { //(2.) Let U <- (-inf, inf) be the initial active slabs... - Comparator comparator = new Comparator() { - @Override - public int compare(Slab o1, Slab o2) { - if (o1.getDistance() < o2.getDistance()) { - return -1; - } - if (o1.getDistance() > o2.getDistance()) { - return 1; - } else { - return 0; - } + Comparator comparator = (o1, o2) -> { + if (o1.getDistance() < o2.getDistance()) { + return -1; + } + if (o1.getDistance() > o2.getDistance()) { + return 1; + } else { + return 0; } }; slabs = new PriorityQueue<>(comparator); @@ -134,13 +131,6 @@ public class LeastMedianOfSquaresEstimator extends Observable implements Algorit this.slabs.remove(slab); } } - if (presenter != null) { - setChanged(); - double m = (getSigmaMin().getX2() + getSigmaMin().getX1()) * -0.5; - double b = (getSigmaMin().getY2() + getSigmaMin().getY1()) * 0.5; - String[] result = {"lms", m+"", b+""}; - notifyObservers(result); - } } /** @@ -359,6 +349,17 @@ public class LeastMedianOfSquaresEstimator extends Observable implements Algorit } + @Override + public void getResult() { + if (presenter != null) { + setChanged(); + double m = (getSigmaMin().getX2() + getSigmaMin().getX1()) * -0.5; + double b = (getSigmaMin().getY2() + getSigmaMin().getY1()) * 0.5; + String[] result = {"lms", m+"", b+""}; + notifyObservers(result); + } + } + /** * Im Allgemeinen werden keine Getter und Setter Methoden benötigt aber sie sind nützlich bei den * JUnit Testfällen. diff --git a/src/main/java/Presenter/Algorithms/RepeatedMedianEstimator.java b/src/main/java/Presenter/Algorithms/RepeatedMedianEstimator.java index ab2cd22..72e042b 100644 --- a/src/main/java/Presenter/Algorithms/RepeatedMedianEstimator.java +++ b/src/main/java/Presenter/Algorithms/RepeatedMedianEstimator.java @@ -113,16 +113,6 @@ public class RepeatedMedianEstimator extends Observable implements Algorithm { contractIntervals(); } - - if (presenter != null) { - setChanged(); - double m = thetaLow * (-1); - double b = ( - (linesInCenterSlab.get(0).getM() * (thetaLow)) + linesInCenterSlab.get(0) - .getB()); - String[] result = {"rm", m+"", b+""}; - notifyObservers(result); - } } /** @@ -347,6 +337,19 @@ public class RepeatedMedianEstimator extends Observable implements Algorithm { } } + @Override + public void getResult() { + if (presenter != null) { + setChanged(); + double m = thetaLow * (-1); + double b = ( + (linesInCenterSlab.get(0).getM() * (thetaLow)) + linesInCenterSlab.get(0) + .getB()); + + String[] result = new String[]{"rm", m+"", b+""}; + notifyObservers(result); + } + } /******************************************************************************************************************* * Getter und Setter Methoden diff --git a/src/main/java/Presenter/Algorithms/TheilSenEstimator.java b/src/main/java/Presenter/Algorithms/TheilSenEstimator.java index eadec10..f2c7b89 100644 --- a/src/main/java/Presenter/Algorithms/TheilSenEstimator.java +++ b/src/main/java/Presenter/Algorithms/TheilSenEstimator.java @@ -6,7 +6,7 @@ import Model.Slab; import Presenter.*; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; +import java.util.Comparator; import java.util.LinkedList; import java.util.Observable; import java.util.concurrent.ThreadLocalRandom; @@ -21,11 +21,11 @@ import java.util.concurrent.ThreadLocalRandom; public class TheilSenEstimator extends Observable implements Algorithm { private Presenter presenter; - private ArrayList set; - private ArrayList intersectionSet; + private ArrayList setOfLines; + private ArrayList setOfIntersections; + private ArrayList intervalIntersections; private ArrayList yCoordinates; private ArrayList xCoordinates; - private Integer numberOfLinesOnLeft; private Slab interval; private Double j; @@ -42,33 +42,35 @@ public class TheilSenEstimator extends Observable implements Algorithm { private Double bVariant; private ArrayList sampledIntersections; - private Double ymin = Double.MAX_VALUE; - private Double ymax = Double.MIN_VALUE; - public TheilSenEstimator(LinkedList set, LinkedList intersectionSet, Presenter presenter) { + public TheilSenEstimator(LinkedList setOfLines, LinkedList setOfIntersections, Presenter presenter) { this.presenter = presenter; - this.intersectionSet = new ArrayList<>(intersectionSet); - this.set = new ArrayList<>(set); - this.n = set.size(); + this.setOfLines = new ArrayList<>(setOfLines); + this.setOfIntersections = new ArrayList<>(setOfIntersections); + this.intervalIntersections = new ArrayList<>(setOfIntersections); + + this.n = setOfLines.size(); this.sampledIntersections = new ArrayList<>(); - Double bin = BinomialCoeffizient.run(n, 2); - this.numberOfLinesOnLeft = 0; this.yCoordinates = new ArrayList<>(); this.xCoordinates = new ArrayList<>(); - - for (Point l : intersectionSet){ - yCoordinates.add(l.getX()); - xCoordinates.add(l.getY()); - } - - this.k = Integer.valueOf((int) (bin / 2)); 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 = -10000d; - b = 10000d; + a = -90000d; + b = 90000d; + + Collections.sort(setOfIntersections); interval = new Slab(a,b); while (true){ @@ -77,29 +79,109 @@ public class TheilSenEstimator extends Observable implements Algorithm { break; } else { r = Double.valueOf(n); - IntersectionCounter counter = new IntersectionCounter(); - int numberOfIntersections = counter.run(set, new Slab(-10000,a)); - k = (int) (BinomialCoeffizient.run(n, 2)/2); + 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.max(1,Math.floor(j - (3 * Math.sqrt(r)))); - jB = (int) Math.min(r-1,Math.floor(j + (3 * Math.sqrt(r)))); + jA = (int) Math.floor(j - (3 * Math.sqrt(r))); + jB = (int) Math.floor(j + (3 * Math.sqrt(r))); do { - sampledIntersections = randomSampleOfIntersections(intersectionSet, r); - //Collections.sort(sampledIntersections); + sampledIntersections = randomSampleOfIntersections(intervalIntersections, r); + Collections.sort(sampledIntersections); aVariant = sampledIntersections.get(jA); bVariant = sampledIntersections.get(jB); - } - while (!checkCondition()); + } while (!checkCondition()); a = aVariant; b = bVariant; interval.setLower(a); interval.setUpper(b); - N = Double.valueOf(checkNumberOfIntersectionInInterval(a,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(); @@ -110,8 +192,8 @@ public class TheilSenEstimator extends Observable implements Algorithm { Collections.sort(yCoordinates); int n = xCoordinates.size(); if (n % 2 == 0){ - x = xCoordinates.get((n/2)-1) + xCoordinates.get((n/2)-2); - y = yCoordinates.get((n/2)-1) + yCoordinates.get((n/2)-2); + 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); @@ -119,59 +201,17 @@ public class TheilSenEstimator extends Observable implements Algorithm { ArrayList resultSt = getKleftMostIntersection(a, this.b); int size = resultSt.size(); - if (n % 2 == 0){ - m = resultSt.get((size/2)-1).getX() + resultSt.get((size/2)-2).getX(); + 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()* (-1); + m = resultSt.get(((size+1)/2)-1).getX(); } - - b = (x * m) + y; m *= -1; + b = (x * m) + y; - String[] result = {"ts", m+"", b+""}; + + String[] result = new String[]{"ts", m+"", b+""}; notifyObservers(result); } } - - private Boolean checkCondition(){ - Boolean cond1 = (intersectionSet.get(k).getX() >= aVariant) && (intersectionSet.get(k).getX() < bVariant); - Boolean cond2 = (checkNumberOfIntersectionInInterval(aVariant,bVariant) <= ((11 * N) / Math.sqrt(r))); - return cond1 && cond2; - } - - - public ArrayList randomSampleOfIntersections(ArrayList set, Double r){ - ArrayList sampledLines = new ArrayList<>(); - - for (int i = 0; i < r; i++) { - sampledLines.add(set.get(ThreadLocalRandom.current().nextInt(0, set.size()-1)).getX()); - } - - return sampledLines; - - } - - - public int checkNumberOfIntersectionInInterval(double a, double b){ - int counter = 0; - for (Point x : intersectionSet){ - if (x.getX() >= a && x.getX() < b){ - counter++; - } - } - return counter; - } - - - public ArrayList getKleftMostIntersection(double a, double b){ - ArrayList list = new ArrayList<>(); - for (Point x : intersectionSet){ - if (x.getX() >= a && x.getX() < b){ - list.add(x); - } - } - - return list; - - } } diff --git a/src/main/java/Presenter/IntersectionCounter.java b/src/main/java/Presenter/IntersectionCounter.java index fff23e9..18f4881 100644 --- a/src/main/java/Presenter/IntersectionCounter.java +++ b/src/main/java/Presenter/IntersectionCounter.java @@ -32,7 +32,14 @@ public class IntersectionCounter { private HashMap secondaryDictionaryBACK; private ArrayList umin; - + /** + * Berechnet die Inversionen zwischen zwei Listen mit Integer Werten. Diese Methode dient als + * Wrapper Methode. Die Logik steht in der countInversions Funktion. + * + * @param a Liste + * @param b Liste + * @return Anzahl an Inversionen + */ public int run(List a, List b) { dictionaryTO = new HashMap<>(); @@ -58,6 +65,14 @@ public class IntersectionCounter { return ret; } + /** + * Wrapper Methode um herauszufinden wieviele Inversionen zwischen den Schnittpunkten der Werte + * in der Liste und den Endpunkten des Intervalls entstehen. + * + * @param set Liste mit Werten (m,b) um Schnittpunkte zu berechnen + * @param slab Interval + * @return Anzahl an Inversionen + */ public int run(List set, Slab slab) { ArrayList listA = new ArrayList<>(); ArrayList listB = new ArrayList<>(); @@ -66,7 +81,16 @@ public class IntersectionCounter { return run(listA, listB); } - + /** + * Methode die, die Daten für die Funktion run vorbereitet. Es werden die Schnittpunkte + * bzgl. der unteren und oberen Grenze des Intervals und den Werten der Liste (m,b) berechnet. Diese + * Werte haben die selbe x Koordinate aber verschiedene y Koordinaten. + * + * @param set Liste mit Werten m,b + * @param slab Interval + * @param listA Schnittpunkte bzgl. unteren Grenze + * @param listB Schnittpunkte bzgl. oberen Grenze + */ private void prepareData(List set, Slab slab, ArrayList listA, ArrayList listB) { secondaryDictionaryTO = new HashMap<>(); @@ -108,11 +132,11 @@ public class IntersectionCounter { * Die Funktion bekommt neben den standard Parametern zusätzlich eine Liste mit Elementen * die als Groundtruth dienen. * - * @param a Eingabefeld mit den Elementen die überprüft werden sollen. + * @param a Eingabefeld mit den Elementen die überprüft werden sollen. * @param start Startpunkt des Eingabefeldes. - * @param end Endpunkt des Eingabefeldes. - * @param aux Groundtruth Ordnung um die Anzahl der Inversionen zu bestimmen. - * @return Anzahl der inversionen zwischen a und aux. + * @param end Endpunkt des Eingabefeldes. + * @param aux Groundtruth Ordnung um die Anzahl der Inversionen zu bestimmen. + * @return Anzahl der inversionen zwischen a und aux. */ public int countInversions(List a, int start, int end, List aux) { if (start >= end) { @@ -149,7 +173,11 @@ public class IntersectionCounter { return invCount; } - + /** + * Diese Methode liefert nur nach dem Ausführen der run Funktion Sinnvolle Werte. + * + * @return Map mit Schnittpunkt Paaren. + */ public HashMap> getIntersectionLinePairs() { ArrayList result = new ArrayList<>(); HashMap> ret = new HashMap<>(); @@ -192,6 +220,11 @@ public class IntersectionCounter { return ret; } + /** + * Diese Methode liefert nur nach dem Ausführen der run Funktion Sinnvolle Werte. + * + * @return x Koordinaten der Schnittpunkte + */ public HashMap calculateIntersectionAbscissas(){ ArrayList result = new ArrayList<>(); HashMap ret = new HashMap<>(); @@ -214,8 +247,13 @@ public class IntersectionCounter { return ret; } - - + /** + * Berechnet die Schnittpunkte zwischen einer gegebenen Gerade und einer Menge an Geraden. + * + * @param set Menge an Geraden + * @param sampledLine eine spezielle Gerade + * @return Liste mit x Koordinaten der Schnittpunkte + */ public ArrayList calculateIntersectionAbscissas(ArrayList set, Line sampledLine){ LinkedList lines = new LinkedList<>(set); ArrayList intersections = new ArrayList<>(); diff --git a/src/main/java/Presenter/Presenter.java b/src/main/java/Presenter/Presenter.java index 5f4a924..acea1d1 100644 --- a/src/main/java/Presenter/Presenter.java +++ b/src/main/java/Presenter/Presenter.java @@ -29,11 +29,6 @@ public class Presenter implements Observer { private Arrangement model; private MainFrame view; - private LeastMedianOfSquaresEstimator lms; - - private Double max; - private Double min; - public Presenter(Arrangement model, MainFrame view) { this.model = model; this.view = view; @@ -134,11 +129,12 @@ public class Presenter implements Observer { if (input[0] != null && input[1] != null){ Double constant = Double.parseDouble(input[0]); Double error = Double.parseDouble(input[1]); - lms = new LeastMedianOfSquaresEstimator(getModel().getLines(), getModel().getNodes(), this); + LeastMedianOfSquaresEstimator lms = new LeastMedianOfSquaresEstimator(getModel().getLines(), getModel().getNodes(), this); lms.setConstant(constant); lms.setQuantileError(error); lms.addObserver(this); lms.run(); + lms.getResult(); } } @@ -149,6 +145,7 @@ public class Presenter implements Observer { rm.setBeta(parameter); rm.addObserver(this); rm.run(); + rm.getResult(); } } @@ -158,6 +155,7 @@ public class Presenter implements Observer { TheilSenEstimator ts = new TheilSenEstimator(getModel().getLines(), getModel().getNodes(),this); ts.addObserver(this); ts.run(); + ts.getResult(); } } @@ -285,19 +283,4 @@ public class Presenter implements Observer { this.model.setLines(lines); } - public Double getMax() { - return max; - } - - public void setMax(Double max) { - this.max = max; - } - - public Double getMin() { - return min; - } - - public void setMin(Double min) { - this.min = min; - } } diff --git a/src/main/java/Presenter/RandomLineSampler.java b/src/main/java/Presenter/RandomLineSampler.java index d212efa..fd27df6 100644 --- a/src/main/java/Presenter/RandomLineSampler.java +++ b/src/main/java/Presenter/RandomLineSampler.java @@ -16,10 +16,10 @@ import java.util.concurrent.ThreadLocalRandom; public class RandomLineSampler { /** - * - * @param set - * @param r - * @return + * Diese Methode liefert eine r Elementige zufällige Stichprobe an Geraden. + * @param set Die gesammtmenge der Geraden aus denen gewählt werden soll + * @param r Anzahl der zu wählenden Geraden + * @return r Elementige zufällige Stichprobe an Geraden */ public static ArrayList run(ArrayList set, Double r, Integer indexOfEnd) { @@ -31,17 +31,4 @@ public class RandomLineSampler { return sampledLines; } - - - - /** - * - * @param set - * @param r - * @return - */ - public static ArrayList run(ArrayList set, Integer r) { - - return run(set,Double.valueOf(r), set.size()); - } }