diff --git a/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java b/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java index 5b6a787..816e4ff 100644 --- a/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java +++ b/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java @@ -19,9 +19,9 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { private LinkedList intersections = new LinkedList<>(); private int n; private double quantileError; - private double kPlus; - private double kMinus; - private ArrayDeque slabs; + private int kPlus; + private int kMinus; + private PriorityQueue slabs; private Slab subSlabU1; private Slab subSlabU2; private Line sigmaMin; @@ -31,51 +31,78 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { public LeastMedianOfSquaresEstimator(LinkedList set, LinkedList intersections) { this.set = set; this.intersections = intersections; + + //(1.) Let n <- |S|; q+ <- q; q- <- q+ * (1 - quantileError);.... + n = set.size(); + double quantile = 0.5; + double qPlus = quantile; + double qMinus = qPlus * (1 - quantileError); + kMinus = (int) Math.ceil(n * qMinus); + kPlus = (int) Math.ceil(n * qPlus); } public void printResult(){ - System.out.println("RESULT: "+sigmaMin.getM()+"x +"+sigmaMin.getB()); + System.out.println("RESULT: X1: "+sigmaMin.getX1() + ", X2: "+sigmaMin.getX2()+"\t Y1: "+sigmaMin.getY1()+", Y2: "+sigmaMin.getY2()); } /** * */ public void approximateLMS() { - //(1.) Let n <- |S|; q+ <- q; q- <- q+ * (1 - quantileError);.... - n = set.size(); - double quantile = 0.5; - double qPlus = quantile; - double qMinus = qPlus * (1 - quantileError); - kMinus = Math.ceil(n * qMinus); - kPlus = Math.ceil(n * qPlus); + //(2.) Let U <- (-inf, inf) be the initial active slabs... - slabs = new ArrayDeque<>(); + 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; + } + }; + slabs = new PriorityQueue<>(comparator); slabs.add(new Slab(-100000, 100000)); heightsigmaMin = Double.MAX_VALUE; //(3.) Apply the following steps as long as the exists active slabs - while (!slabs.isEmpty()) { - Slab slab = slabs.getFirst(); - //(a.) Select any active Slab and calc. the inversions - int numberOfIntersections = countInversions(slab); + boolean active = true; + Slab slab; + while (!this.slabs.isEmpty()) { + slab = this.slabs.peek(); + if (slab.getActivity()){ + //(a.) Select any active Slab and calc. the inversions + int numberOfIntersections = countInversions(slab); - //(b.) apply plane sweep - int constant = 1; - if (numberOfIntersections < (constant * n)) { - sigmaMin = planeSweep(slab); - } else {//(c.) otherwise.... - //get random intersections point... - splitActiveSlab(intersectionsPoint, slab); + //(b.) apply plane sweep + int constant = 1; + if ((constant * n) >= numberOfIntersections) { + sigmaMin = planeSweep(slab); + } else {//(c.) otherwise.... + //get random intersections point... + splitActiveSlab(intersectionsPoint, slab); + + //(d.) this may update sigma min + upperBound(intersectionsPoint); + //(e.) for i={1,2}, call lower bound(Ui) + lowerBound(subSlabU1); + lowerBound(subSlabU2); + + if (subSlabU1.getActivity()){ + this.slabs.add(subSlabU1); + } + if (subSlabU2.getActivity()){ + this.slabs.add(subSlabU2); + } + } + } else { + this.slabs.remove(slab); } - //(d.) this may update sigma min - upperBound(intersectionsPoint); - //(e.) for i={1,2}, call lower bound(Ui) - lowerBound(subSlabU1); - lowerBound(subSlabU2); - } -// printResult(); + + } } /** @@ -98,13 +125,16 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { numberOfInversions = mergeSort(umin, 0, umin.size() - 1, umax); for (Point point : intersections) { - if (point.getX() >= slab.getLower() && point.getX() < slab.getUpper()) { + if (point.getX() > slab.getLower() && point.getX() < slab.getUpper()) { randomIntersection.add(point.getX()); } } Collections.shuffle(randomIntersection); - intersectionsPoint = randomIntersection.get(0); + int access = (int) ( randomIntersection.size() * 0.5); + if (!randomIntersection.isEmpty()){ + intersectionsPoint = randomIntersection.get(access); + } return numberOfInversions; } @@ -112,12 +142,14 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { //Parameter anpassen /** - * - * @param a - * @param start - * @param end - * @param aux - * @return + * Angepasster Merge-Sort Algorithmus. + * 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 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. */ public int mergeSort(List a, int start, int end, List aux) { if (start >= end) { @@ -169,61 +201,70 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { double heightOfBracelet = heightsigmaMin; for (Point current : xQueue){ - double[] currentBracelet = calcKMinusBracelet(current); + Double[] currentBracelet = calcKMinusBracelet(current, kMinus); if (currentBracelet == null){ continue; } else if (currentBracelet[0] < heightOfBracelet){ heightOfBracelet = currentBracelet[0]; bracelet = new Line(current.getX(), current.getX(), currentBracelet[1], currentBracelet[2]); - System.out.println("R: "+bracelet.getM()+"x +"+bracelet.getB()); } } - + slab.setActivity(false); return bracelet; } /** - * @param point + * Diese Methode spaltet den aktiven Slab an der x Koordinate point. Es werden zwei neue Slabs erzeugt. + * @param point x Koordinate an der, der Split geschieht. */ public void splitActiveSlab(double point, Slab active) { - subSlabU1 = new Slab(active.getLower(), point); subSlabU2 = new Slab(point, active.getUpper()); - this.slabs.removeFirst(); + + this.slabs.remove(active); } /** + * * @param point */ public void upperBound(double point) { - double height; - + double height = heightsigmaMin; + double tmpHeight; ArrayList sortedLineSequence = getEjValues(point); - for (int i = 1; i < (n - (kMinus + 1)); i++) { - height = sortedLineSequence.get(i + (((int) kMinus) - 1)) - sortedLineSequence.get(i); + + int itnbr = ((n - kMinus) + 1); + for (int i = 0; i < itnbr; i++) { + tmpHeight = sortedLineSequence.get((i + kMinus) - 1) - sortedLineSequence.get(i); + if (tmpHeight < height){ + height = tmpHeight; + } if (height < heightsigmaMin) { - sigmaMin.setEndPoints(point, sortedLineSequence.get(i + (((int) kMinus) - 1)) - ,point, sortedLineSequence.get(i)); + heightsigmaMin = height; + if (sigmaMin != null){ + sigmaMin.setEndPoints(point, sortedLineSequence.get(i) + ,point, sortedLineSequence.get((i + kMinus) - 1)); + } else { + sigmaMin = new Line(point, point, sortedLineSequence.get(i), sortedLineSequence.get((i + kMinus) - 1)); + } } } } /** - * @param slab + * @param pslab * @return */ - public void lowerBound(Slab slab) { + public void lowerBound(Slab pslab) { int[] alpha = new int[n]; int[] beta = new int[n]; - alpha[0] = 0; - beta[0] = 0; int strictlyGreater = 0; //Teil I. @@ -231,50 +272,62 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { ArrayList uminList; //y koordinaten der Schnittpunkte - ArrayList lines = new ArrayList<>(); - System.out.println("Anzahl der Slabs: "+this.slabs.size()); + ArrayList lines = new ArrayList<>(); for (Line p : set) { - lines.add(new Point(((slab.getLower() * p.getM()) + p.getB()), ((slab.getUpper() * p.getM()) + p.getB()))); + lines.add(new Line(pslab.getLower(), pslab.getUpper(),((pslab.getLower() * p.getM()) + p.getB()), ((pslab.getUpper() * p.getM()) + p.getB()))); } + umaxList = getEjValues(pslab.getUpper()); + uminList = getEjValues(pslab.getLower()); - umaxList = getEjValues(slab.getUpper()); - uminList = getEjValues(slab.getLower()); - - for (int i = 1; i < n; i++) { - Point level = new Point(uminList.get(i), umaxList.get(i)); - for (Point point : lines) { - if ((point.getX() < level.getX()) && (point.getY() < level.getY())) { + for (int i = 0; i < n; i++) { + Line level = new Line(pslab.getLower(),pslab.getUpper(),uminList.get(i), umaxList.get(i)); + for (Line line : lines) { + if ((line.getY1() < level.getY1()) && (line.getY2() < level.getY2())) { alpha[i]++; } - if ((point.getX() > level.getX()) && (point.getY() > level.getY())) { + if ((line.getY1() > level.getY1()) && (line.getY2() > level.getY2())) { strictlyGreater++; } } beta[i] = n - (alpha[i] + strictlyGreater); + strictlyGreater = 0; } + //TEST der Alpha und Beta werte, siehe JUnit Test + //for (int i=0;i= n) { + //System.out.println("i: "+i+", j:"+j+". ungültig"); + pslab.setActivity(false); break; } else { - h = Math.min((uminList.get(j) - uminList.get(i)), (umaxList.get(j) - umaxList.get(i))); + h = Math.min(Math.abs(uminList.get(j) - uminList.get(i)), Math.abs(umaxList.get(j) - umaxList.get(i))); + double error = 0.01; + if (((1 + error) * h) < heightsigmaMin) { + //System.out.println("h: "+ h +" ist kleiner als height(sigmaMin): "+heightsigmaMin); + pslab.setActivity(true); + return; + } } + i = 0; } - double error = 0.01; - System.out.println("h: "+h); - if (((1 + error) * h) < heightsigmaMin) { - this.slabs.addLast(slab); - } + } /** @@ -298,24 +351,26 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { } /** - * - * @param x - * @return + * Die Funktion berechnet anhand einer vertikalen Gerade x = px das sogenannte kleinste kMinus Bracelet. + * Mit anderen Worten es wird eine vertikale Teilgerade berechnet die mindestens kMinus Geraden schneidet + * und dabei minimal ist. + * @param px Koordinate um die "vertikale Gerade" zu simulieren. + * @return Das Array enthält höhe des Bracelet, e_j und e_(j + kMinus - 1) */ - public double[] calcKMinusBracelet(Point x) { + public Double[] calcKMinusBracelet(Point px, int kMinusValue) { //y Koordinaten für das kMinus brecalet LinkedList intersections = new LinkedList<>(); for (Line line : set) { - intersections.add((x.getX() * line.getM())+line.getB()); + intersections.add((px.getX() * line.getM())+line.getB()); } - if (intersections.size() < kMinus){ - return null; - } else { + if (intersections.size() >= kMinusValue){ Collections.sort(intersections); - double height = Math.abs(intersections.getFirst() - intersections.getLast()); - double[] ret = {height, intersections.getFirst(), intersections.getLast()}; + double height = Math.abs(intersections.get(0) - intersections.get(0 + kMinusValue - 1)); + Double[] ret = {height, intersections.get(0), intersections.get(0 + kMinusValue - 1)}; return ret; + } else { + return null; } } @@ -324,7 +379,7 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { * Hilfsklasse um die Slabs zu verteilen, private Klasse da sonst nicht verwendett wird und somit eine * äußere Klasse überflüssig ist... */ - private static class Slab { + protected static class Slab { private double upper; private double lower; private Boolean activity; @@ -332,6 +387,7 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { public Slab(double lower, double upper) { this.upper = upper; this.lower = lower; + this.activity = true; } public Boolean getActivity() { @@ -358,5 +414,103 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { this.lower = lower; } + public Double getDistance(){ + + return Math.abs(this.upper - this.lower); + } + + } + + + /** + * Im Allgemeinen werden keine Getter und Setter Methoden benötigt aber sie sind nützlich bei den JUnit Testfällen. + */ + + public LinkedList getSet() { + return set; + } + + public void setSet(LinkedList set) { + this.set = set; + } + + public LinkedList getIntersections() { + return intersections; + } + + public void setIntersections(LinkedList intersections) { + this.intersections = intersections; + } + + public int getN() { + return n; + } + + public void setN(int n) { + this.n = n; + } + + public double getQuantileError() { + return quantileError; + } + + public void setQuantileError(double quantileError) { + this.quantileError = quantileError; + } + + public int getkPlus() { + return kPlus; + } + + public void setkPlus(int kPlus) { + this.kPlus = kPlus; + } + + public int getkMinus() { + return kMinus; + } + + public void setkMinus(int kMinus) { + this.kMinus = kMinus; + } + + public Slab getSubSlabU1() { + return subSlabU1; + } + + public void setSubSlabU1(Slab subSlabU1) { + this.subSlabU1 = subSlabU1; + } + + public Slab getSubSlabU2() { + return subSlabU2; + } + + public void setSubSlabU2(Slab subSlabU2) { + this.subSlabU2 = subSlabU2; + } + + public Line getSigmaMin() { + return sigmaMin; + } + + public void setSigmaMin(Line sigmaMin) { + this.sigmaMin = sigmaMin; + } + + public double getHeightsigmaMin() { + return heightsigmaMin; + } + + public void setHeightsigmaMin(double heightsigmaMin) { + this.heightsigmaMin = heightsigmaMin; + } + + public double getIntersectionsPoint() { + return intersectionsPoint; + } + + public void setIntersectionsPoint(double intersectionsPoint) { + this.intersectionsPoint = intersectionsPoint; } } diff --git a/src/test/java/Presenter/Algorithms/LeastMedianOfSquaresEstimatorTest.java b/src/test/java/Presenter/Algorithms/LeastMedianOfSquaresEstimatorTest.java index dea4976..829b910 100644 --- a/src/test/java/Presenter/Algorithms/LeastMedianOfSquaresEstimatorTest.java +++ b/src/test/java/Presenter/Algorithms/LeastMedianOfSquaresEstimatorTest.java @@ -8,6 +8,7 @@ import org.junit.Test; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import static org.junit.Assert.*; @@ -26,12 +27,19 @@ public class LeastMedianOfSquaresEstimatorTest { @Before public void setUp() throws Exception { - LinkedList line = new LinkedList<>(); + Double[] x = {18d,24d,30d,34d,38d}; + Double[] y = {18d,26d,30d,40d,70d}; + + LinkedList lines = new LinkedList<>(); LinkedList intersections = new LinkedList<>(); + for (int i=0; i<5; i++) + lines.add(new Line(x[i], y[i])); - lms = new LeastMedianOfSquaresEstimator(line, intersections); + + + lms = new LeastMedianOfSquaresEstimator(lines, intersections); } @Test @@ -62,4 +70,55 @@ public class LeastMedianOfSquaresEstimatorTest { } + @Test + public void geEjValues() throws Exception { + + Double[] expected = {36d,50d,60d,74d,108d}; + ArrayList actual = lms.getEjValues(1d); + assertArrayEquals(expected, actual.toArray()); + } + + @Test + public void calcKMinusBracelet() throws Exception { + + Point point = new Point(1d, 1d); + Double[] expected = {24d, 36d, 60d}; + Double[] actual = lms.calcKMinusBracelet(point, 3); + + assertArrayEquals(expected, actual); + + } + + @Test + public void upperBound() throws Exception { + lms.setkMinus(3); + lms.setHeightsigmaMin(500); + lms.setSigmaMin(new Line(0,0,0,0)); + + Line expected = new Line(5,5,146,210); + lms.upperBound(5d); + + assertEquals(expected.getX1(), lms.getSigmaMin().getX1(),0.01); + assertEquals(expected.getX2(), lms.getSigmaMin().getX2(),0.01); + assertEquals(expected.getY1(), lms.getSigmaMin().getY1(),0.01); + assertEquals(expected.getY2(), lms.getSigmaMin().getY2(),0.01); + } + + @Test + public void lowerBound() throws Exception { + //kann nur über sout geprüft werden test passt aber + Double[] expectedAlpha = {0d,0d,0d,2d,4d}; + Double[] expectedBeta = {2d,4d,4d,2d,1d}; + lms.setHeightsigmaMin(500); + + LeastMedianOfSquaresEstimator.Slab slab = new LeastMedianOfSquaresEstimator.Slab(-2,0); + lms.lowerBound(slab); + assertTrue(slab.getActivity()); + } + + @Test + public void planeSweep() throws Exception { + + } + } \ No newline at end of file