package Presenter.Algorithms; import Model.Interval; import Model.Line; import Presenter.*; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.Observable; import java.util.Random; 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 RepeatedMedianEstimator extends Observable implements Algorithm { private Presenter presenter; private LinkedList set; private HashMap> linePairs; private HashMap medianIntersections = new HashMap<>(); private HashMap> intersectionAbscissas = new HashMap<>(); private Interval interval; //in der Literatur als L_i, C_i, und R_i bekannt private ArrayList countLeftSlab; private ArrayList countCenterSlab; private ArrayList countRightSlab; //die Mengen L,C und R private ArrayList linesInLeftSlab; private ArrayList linesInCenterSlab; private ArrayList linesInRightSlab; private Double r; private Integer n; private Double k; private Double kLow; private Double kHigh; private Double beta; private Double thetaLow; private Double thetaHigh; public RepeatedMedianEstimator(LinkedList set, Presenter presenter) { this.set = set; this.presenter = presenter; interval = new Interval(-10000, 10000); n = set.size(); beta = 0.5; countLeftSlab = new ArrayList<>(); countCenterSlab = new ArrayList<>(); countRightSlab = new ArrayList<>(); for (int i = 0; i < n; i++) { countLeftSlab.add(0); countRightSlab.add(0); countCenterSlab.add(n - 1); intersectionAbscissas.put(set.get(i), new ArrayList<>()); } linesInLeftSlab = new ArrayList<>(); linesInCenterSlab = new ArrayList<>(set); linesInRightSlab = new ArrayList<>(); linePairs = new HashMap<>(); } /** * */ public void run() { while (linesInCenterSlab.size() != 1) { n = linesInCenterSlab.size(); r = Math.ceil(Math.pow(n, beta)); ArrayList lines = RandomLineSampler.run(linesInCenterSlab, r, linesInCenterSlab.size()); //For each Sampled Line, compute its median intersection abscissa ArrayList medianIntersectionAbscissas = new ArrayList<>(); for (Line l : lines) { Double abscissa = estimateMedianIntersectionAbscissas(l); medianIntersections.put(l, abscissa); medianIntersectionAbscissas.add(abscissa); } //rank of the repeated median in C k = Math.max(1,Math.min(set.size(),(Math.ceil(n * 0.5) - linesInLeftSlab.size()))); //compute k_lo and k_hi computeSlabBorders(); // if (medianIntersectionAbscissas.size() < kLow || medianIntersectionAbscissas.size() sampleLines(ArrayList set, Double r) { ArrayList sampledLines = new ArrayList<>(); for (int i = 0; i < r; i++) { sampledLines.add(set.get(ThreadLocalRandom.current().nextInt(0, linesInCenterSlab.size()))); } return sampledLines; } /** * * @param sampledLine * @return */ public Double estimateMedianIntersectionAbscissas(Line sampledLine) { Integer index = Integer.parseInt(sampledLine.getId()); ArrayList intersections = new ArrayList<>(); double intersection; IntersectionCounter intersectionCounter = new IntersectionCounter(); intersections = intersectionCounter.calculateIntersectionAbscissas(linesInCenterSlab, sampledLine); Collections.sort(intersections); double ki = Math.ceil((n - 1) / 2) - countLeftSlab.get(index); double i = (Math.ceil((Math.sqrt(n) * ki) / countCenterSlab.get(index))); int accessIndex; if (i < 0) accessIndex = 0; else if (i >= intersections.size()) accessIndex = intersections.size()-1; else accessIndex = (int) i; //System.out.println(accessIndex); return intersections.get(accessIndex); } /** * */ public void computeSlabBorders() { kLow = Math .max(1, Math.floor( ( (r * k) / (linesInCenterSlab.size())) - ( (3 * Math.sqrt(r)) / (2)) ) ); kHigh = Math .min(r, Math.floor( ((r * k) / (linesInCenterSlab.size())) + ((3 * Math.sqrt(r)) / (2)) ) ); } /** * * @param a * @param i * @return */ public Double randomizedSelect(ArrayList a, double i) { int start = 0; int end = a.size()-1; if (i >= end+1){ return a.get(end); } while(true){ if(start == end){ return a.get(start); } int q = randomizedPartition(a, start, end); int k = q-start+1; if(i == k){ return a.get(q); } else{ if(i a, int start, int end) { int i = 0; Random random = new Random(System.currentTimeMillis()); //alternative: ThreadLocalRandom.current() if(start < end){ i = start + random.nextInt(end-start); }else{ i = end + random.nextInt(start-end); } Collections.swap(a, end, i); return partition(a, start, end); } /** * * @param a * @param start * @param end * @return */ public int partition(ArrayList a, int start, int end) { Double x = a.get(end); int i = start - 1; for (int j = start; j <= end-1; j++) { if (a.get(j) <= x) { i++; Collections.swap(a, i, j); } } Collections.swap(a, i+1, end); return i+1; } /** * */ public void countNumberOfIntersectionsAbscissas() { for (Line line : linesInCenterSlab) { ArrayList intersections = intersectionAbscissas.get(line); Integer index = Integer.parseInt(line.getId()); int left = 0; int center = 0; int right = 0; for (Double intersection : intersections) { if (intersection <= thetaLow) { left++; } else if (intersection > thetaLow && intersection <= thetaHigh) { center++; } else if (intersection > thetaHigh){ right++; } } //System.out.println("Linie: "+line.getId()+"\tLeft: "+left+"\t Center: "+center+"\t Right: "+right); countLeftSlab.set(index, left); countCenterSlab.set(index, center); countRightSlab.set(index, right); } } /** * */ public void contractIntervals() { for (int i = 0; i < linesInCenterSlab.size(); i++) { int left = countLeftSlab.get(i); int center = countCenterSlab.get(i); int right = countRightSlab.get(i); int max = Math.max(left, Math.max(center, right)); if (left == max){ linesInLeftSlab.add(linesInCenterSlab.get(i)); linesInCenterSlab.remove(i); } else if (right == max) { linesInRightSlab.add(linesInCenterSlab.get(i)); linesInCenterSlab.remove(i); } // if (medianIntersections.get(linesInCenterSlab.get(i)) != null) { // if (medianIntersections.get(linesInCenterSlab.get(i)) <= thetaLow) { // linesInLeftSlab.add(linesInCenterSlab.get(i)); // linesInCenterSlab.remove(i); // countLeftSlab.set(i, countLeftSlab.get(i) + 1); // countCenterSlab.set(i, countCenterSlab.get(i) - 1); // } else if (medianIntersections.get(linesInCenterSlab.get(i)) > thetaHigh) { // linesInRightSlab.add(linesInCenterSlab.get(i)); // linesInCenterSlab.remove(i); // countRightSlab.set(i, countRightSlab.get(i) + 1); // countCenterSlab.set(i, countCenterSlab.get(i) - 1); // } // } // } // } //wähle C als C if (linesInLeftSlab.size() < Math.ceil(n/2) && Math.ceil(n/2) <= linesInLeftSlab.size()+linesInCenterSlab.size()){ interval.setLower(thetaLow + 0.1); interval.setUpper(thetaHigh); } // wähle L als C else if (Math.ceil(n/2) <= linesInLeftSlab.size()){ interval.setUpper(thetaLow); } //wähle R als C else if (linesInLeftSlab.size()+linesInCenterSlab.size() < Math.ceil(n/2) && Math.ceil(n/2) <= (linesInLeftSlab.size()+linesInCenterSlab.size()+linesInRightSlab.size()) ){ interval.setLower(thetaHigh - 0.1); } } @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 ******************************************************************************************************************/ public LinkedList getSet() { return set; } public void setSet(LinkedList set) { this.set = set; } public HashMap> getLinePairs() { return linePairs; } public void setLinePairs(HashMap> linePairs) { this.linePairs = linePairs; } public HashMap getMedianIntersections() { return medianIntersections; } public void setMedianIntersections(HashMap medianIntersections) { this.medianIntersections = medianIntersections; } public HashMap> getIntersectionAbscissas() { return intersectionAbscissas; } public void setIntersectionAbscissas( HashMap> intersectionAbscissas) { this.intersectionAbscissas = intersectionAbscissas; } public Interval getInterval() { return interval; } public void setInterval(Interval interval) { this.interval = interval; } public ArrayList getCountLeftSlab() { return countLeftSlab; } public void setCountLeftSlab(ArrayList countLeftSlab) { this.countLeftSlab = countLeftSlab; } public ArrayList getCountCenterSlab() { return countCenterSlab; } public void setCountCenterSlab(ArrayList countCenterSlab) { this.countCenterSlab = countCenterSlab; } public ArrayList getCountRightSlab() { return countRightSlab; } public void setCountRightSlab(ArrayList countRightSlab) { this.countRightSlab = countRightSlab; } public ArrayList getLinesInLeftSlab() { return linesInLeftSlab; } public void setLinesInLeftSlab(ArrayList linesInLeftSlab) { this.linesInLeftSlab = linesInLeftSlab; } public ArrayList getLinesInCenterSlab() { return linesInCenterSlab; } public void setLinesInCenterSlab(ArrayList linesInCenterSlab) { this.linesInCenterSlab = linesInCenterSlab; } public ArrayList getLinesInRightSlab() { return linesInRightSlab; } public void setLinesInRightSlab(ArrayList linesInRightSlab) { this.linesInRightSlab = linesInRightSlab; } public Double getR() { return r; } public void setR(Double r) { this.r = r; } public Integer getN() { return n; } public void setN(Integer n) { this.n = n; } public Double getK() { return k; } public void setK(Double k) { this.k = k; } public Double getkLow() { return kLow; } public void setkLow(Double kLow) { this.kLow = kLow; } public Double getkHigh() { return kHigh; } public void setkHigh(Double kHigh) { this.kHigh = kHigh; } public Double getBeta() { return beta; } public void setBeta(Double beta) { this.beta = beta; } public Double getThetaLow() { return thetaLow; } public void setThetaLow(Double thetaLow) { this.thetaLow = thetaLow; } public Double getThetaHigh() { return thetaHigh; } public void setThetaHigh(Double thetaHigh) { this.thetaHigh = thetaHigh; } }