diff --git a/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java b/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java index 3b116ad..850e1a8 100644 --- a/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java +++ b/src/main/java/Presenter/Algorithms/LeastMedianOfSquaresEstimator.java @@ -1,7 +1,6 @@ package Presenter.Algorithms; import Model.Coordinates; -import sun.awt.image.ImageWatched; import java.util.*; @@ -16,9 +15,11 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { private LinkedList set = new LinkedList<>(); - private LinkedList sortedIntersections = new LinkedList<>(); + private LinkedList intersections = new LinkedList<>(); + private int n; - private double quantile = 0.5; + private final double quantile = 0.5; + private final double error = 0.01; private double quantileError; private double qPlus; private double qMinus; @@ -28,8 +29,7 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { private Slab activeSlab; private Slab subSlabU1; private Slab subSlabU2; - private double umin; - private double umax; + private ArrayList sortedLineSequence = new ArrayList<>(); private double heightsigmaMin; private Coordinates sigmaMinStart; private Coordinates sigmaMinEnd; @@ -42,58 +42,67 @@ 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 { - private double upper; - private double lower; - - public Slab(double lower, double upper) { - this.upper = upper; - this.lower = lower; - } - - public double getUpper() { - return upper; - } - - public void setUpper(double upper) { - this.upper = upper; - } - - public double getLower() { - return lower; - } - - public void setLower(double lower) { - this.lower = lower; - } + private static class Slab { + private double upper; + private double lower; + private Boolean activity; + public Slab(double lower, double upper) { + this.upper = upper; + this.lower = lower; } + public Boolean getActivity() { + return activity; + } - public void approximateLMS(){ + public void setActivity(Boolean isActive) { + this.activity = isActive; + } + + public double getUpper() { + return upper; + } + + public void setUpper(double upper) { + this.upper = upper; + } + + public double getLower() { + return lower; + } + + public void setLower(double lower) { + this.lower = lower; + } + + } + + + public void approximateLMS() { //(1.) Let n <- |S|; q+ <- q; q- <- q+ * (1 - quantileError);.... n = set.size(); - qPlus = quantile; + qPlus = quantile; qMinus = qPlus * (1 - quantileError); kMinus = Math.ceil(n * qMinus); - kPlus = Math.ceil(n * qPlus); + kPlus = Math.ceil(n * qPlus); //(2.) Let U <- (-inf, inf) be the initial active slab... slab = new TreeSet<>(); slab.add(new Slab(Double.MAX_VALUE, Double.MIN_VALUE)); - heightsigmaMin = Double.MAX_VALUE; + heightsigmaMin = Double.MAX_VALUE; //(3.) Apply the following steps as long as the exists active slabs - for(Iterator it = slab.iterator(); it.hasNext();){ + for (Iterator it = slab.iterator(); it.hasNext(); ) { //(a.) Select any active Slab and calc. the inversions activeSlab = it.next(); numberOfIntersections = countInversions(activeSlab); //(b.) apply plane sweep - if ( numberOfIntersections < (constant * n)){ + if (numberOfIntersections < (constant * n)) { kMinusBracelet = planeSweep(activeSlab); } else {//(c.) otherwise.... - //get random intersections point... + //get random intersections point... splitActiveSlab(intersectionsPoint); } //(d.) this may update sigma min @@ -106,50 +115,221 @@ public class LeastMedianOfSquaresEstimator extends Algorithm { } //Parameter anpassen - public int countInversions(Slab slab){ - return 0; + + /** + * @param slab + * @return + */ + public int countInversions(Slab slab) { + + int numberOfInversions = 0; + + ArrayList umin = new ArrayList<>(); + ArrayList umax = new ArrayList<>(); + + for (Coordinates p : set) { + umin.add((slab.getLower() * p.getX()) + p.getY()); + umax.add((slab.getUpper() * p.getX()) + p.getY()); + } + + numberOfInversions = mergeSort(umin, 0, umin.size() - 1, umax); + + for (Coordinates point : intersections) { + if (point.getX() >= slab.getLower() && point.getX() < slab.getUpper()) { + intersectionsPoint = point.getX(); + break; + } + } + + + return numberOfInversions; } - public Coordinates planeSweep(Slab slab){ + public int mergeSort(List a, int start, int end, List aux) { + if (start >= end) { + return 0; + } + int invCount = 0; + int mid = start + (end - start) / 2; + int invCountLeft = mergeSort(a, start, mid, aux); // divide and conquer + int invCountRight = mergeSort(a, mid + 1, end, aux); // divide and conquer + invCount += (invCountLeft + invCountRight); + for (int i = start; i <= end; i++) { + aux.set(i, a.get(i)); + } + int left = start; + int right = mid + 1; + int index = start; + while (left <= mid && right <= end) { + if (aux.get(left) < aux.get(right)) { + a.set(index++, aux.get(left++)); + } else { + a.set(index++, aux.get(right++)); + invCount += mid - left + 1; // number of inversions for aux[right] + } + } + while (left <= mid) { + a.set(index++, aux.get(left++)); + } + // no need to copy over remaining aux[right++] because they are already inside a + return invCount; + } + + /** + * @param slab + * @return + */ + public Coordinates planeSweep(Slab slab) { + Comparator queueComparator = (o1, o2) -> { + if (o1.getX() == o2.getX()) { + if (o1.getY() <= o2.getY()) { + return -1; + } else { + return 1; + } + } else if (o1.getX() < o2.getX()) { + return -1; + } else { + return 1; + } + }; + PriorityQueue xQueue = new PriorityQueue<>(queueComparator); + Comparator treeComparator = (o1, o2) -> { + if (o1.getY() == o2.getY()) { + if (o1.getX() <= o2.getX()) { + return -1; + } else { + return 1; + } + } else if (o1.getY() < o2.getY()) { + return -1; + } else { + return 1; + } + }; + TreeMap yStruct = new TreeMap(treeComparator); + + for (Coordinates point : intersections) { + if (point.getX() >= slab.getLower() && point.getX() < slab.getUpper()) { + xQueue.add(point); + } + } + + + return new Coordinates(.0, .0); } - public void splitActiveSlab(double point){ + /** + * @param point + */ + public void splitActiveSlab(double point) { + subSlabU1 = new Slab(activeSlab.getLower(), point); subSlabU2 = new Slab(point, activeSlab.getUpper()); } - public void upperBound(double point){ - ArrayList temp = new ArrayList<>(); + /** + * @param point + */ + public void upperBound(double point) { + ArrayList min = new ArrayList<>(); double height; - for (Coordinates p : set) { - temp.add(new Coordinates(point, (p.getX() * point) + p.getY())); - } - Collections.sort(temp); + sortedLineSequence = getEjValues(point); - for (int i=1;i<(n-(kMinus+1));i++){ - height = temp.get(i+(((int) kMinus) - 1)).getY() - temp.get(i).getY(); + for (int i = 1; i < (n - (kMinus + 1)); i++) { + height = sortedLineSequence.get(i + (((int) kMinus) - 1)) - sortedLineSequence.get(i); - if (height < heightsigmaMin) - sigmaMinStart = new Coordinates(point, temp.get(i+(((int) kMinus) - 1)).getY()); - sigmaMinEnd = new Coordinates(point, temp.get(i).getY()); + if (height < heightsigmaMin) { + sigmaMinStart = new Coordinates(point, sortedLineSequence.get(i + (((int) kMinus) - 1))); + sigmaMinEnd = new Coordinates(point, sortedLineSequence.get(i)); + } } } - public void lowerBound(Slab slab){ - double[] alpha = new double[n]; - double[] beta = new double[n]; + /** + * @param slab + * @return + */ + public Slab lowerBound(Slab slab) { + boolean active = false; + int[] alpha = new int[n]; + int[] beta = new int[n]; alpha[0] = 0; - beta[0] = 0; + beta[0] = 0; + int strictlyGreater = 0; - for (int i=1;i < n; i++){ - + //Teil I. + ArrayList umaxList; + ArrayList uminList; + + //y koordinaten der Schnittpunkte + ArrayList lines = new ArrayList<>(); + for (Coordinates p : set) { + lines.add(new Coordinates(((slab.getLower() * p.getX()) + p.getY()), ((slab.getUpper() * p.getX()) + p.getY()))); } - // if Ui is active on return add it to the list of active slabs..!!! + + umaxList = getEjValues(slab.getUpper()); + uminList = getEjValues(slab.getLower()); + + for (int i = 1; i < n; i++) { + Coordinates level = new Coordinates(uminList.get(i), umaxList.get(i)); + for (Coordinates point : lines) { + if ((point.getX() < level.getX()) && (point.getY() < level.getY())) { + alpha[i]++; + } + + if ((point.getX() > level.getX()) && (point.getY() > level.getY())) { + strictlyGreater++; + } + } + beta[i] = n - (alpha[i] + strictlyGreater); + } + + //Teil II. + int i = 1; + double h = Double.MAX_VALUE; + active = false; + for (int j = 0; j < n; j++) { + do { + i++; + } while ((i < n) && (beta[i] - alpha[j] < kPlus)); + + if (i > n) { + slab.setActivity(false); + break; + } + + h = Math.min((uminList.get(j) - uminList.get(i)), (umaxList.get(j) - umaxList.get(i))); + } + if (((1 + error) * h) < heightsigmaMin) { + slab.setActivity(true); + } + return slab; + } + + /** + * Berechnet die Schnittpunkte der Geraden und der vertikalen Gerade u. Im paper sind diese Werte als e_j Werte + * bekannt. + * + * @param u vertikale Gerade + * @return Liste der Schnittpunkte (da u bekannt werden nur die y Werte zurück gegeben) + */ + public ArrayList getEjValues(double u) { + + ArrayList ret = new ArrayList<>(); + + for (Coordinates p : set) { + ret.add((p.getX() * u) + p.getY()); + } + + Collections.sort(ret); + + return ret; } } diff --git a/src/test/java/Presenter/Algorithms/LeastMedianOfSquaresEstimatorTest.java b/src/test/java/Presenter/Algorithms/LeastMedianOfSquaresEstimatorTest.java new file mode 100644 index 0000000..58bcc78 --- /dev/null +++ b/src/test/java/Presenter/Algorithms/LeastMedianOfSquaresEstimatorTest.java @@ -0,0 +1,73 @@ +package Presenter.Algorithms; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; + +import static org.junit.Assert.*; + +/** + * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. + * + * @Author: Armin Wolf + * @Email: a_wolf28@uni-muenster.de + * @Date: 12.06.2017. + */ +public class LeastMedianOfSquaresEstimatorTest { + + private LeastMedianOfSquaresEstimator lms; + + @Before + public void setUp() throws Exception { + lms = new LeastMedianOfSquaresEstimator(); + } + + @Test + public void approximateLMS() throws Exception { + } + + + @Test + public void mergeSort() throws Exception { + double[] umin = {1,5,6,4,20}; + double[] umax = {1,4,6,5,20}; + + ArrayList a = new ArrayList<>(); + ArrayList b = new ArrayList<>(); + + for (double d :umin) { + a.add(d); + } + + for (double d :umax) { + b.add(d); + } + + + int ret = lms.mergeSort(a,0,a.size()-1,b); + assertEquals(2, ret); + + } + + @Test + public void planeSweep() throws Exception { + } + + @Test + public void splitActiveSlab() throws Exception { + } + + @Test + public void upperBound() throws Exception { + } + + @Test + public void lowerBound() throws Exception { + } + + @Test + public void getEjValues() throws Exception { + } + +} \ No newline at end of file