package presenter.algorithms.advanced; import model.Interval; import model.Line; import presenter.Presenter; import presenter.algorithms.Algorithm; import presenter.algorithms.util.FastElementSelector; import presenter.algorithms.util.IntersectionCounter; import presenter.algorithms.util.RandomSampler; import java.util.ArrayList; import java.util.HashMap; 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 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; private Double slope; private Double yInterception; 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(0d); countRightSlab.add(0d); countCenterSlab.add(n - 1.0); intersectionAbscissas.put(set.get(i), new ArrayList<>()); } linesInLeftSlab = new ArrayList<>(); linesInCenterSlab = new ArrayList<>(set); linesInRightSlab = new ArrayList<>(); linePairs = new HashMap<>(); } public RepeatedMedianEstimator(LinkedList set) { this(set, null); } /** * */ public void run() { while (linesInCenterSlab.size() != 1) { n = linesInCenterSlab.size(); r = Math.ceil(Math.pow(n, beta)); ArrayList lines = RandomSampler.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))); double ki = Math.ceil((n - 1) / 2) - FastElementSelector.randomizedSelect(countLeftSlab, index); double i = (Math.ceil((Math.sqrt(n) * ki) / FastElementSelector.randomizedSelect(countCenterSlab, 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); return FastElementSelector.randomizedSelect(intersections, 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)) ) ); } /** * */ 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, (double) left); countCenterSlab.set(index, (double) center); countRightSlab.set(index, (double) right); } } /** * */ public void contractIntervals() { for (int i = 0; i < linesInCenterSlab.size(); i++) { double left = countLeftSlab.get(i); double center = countCenterSlab.get(i); double right = countRightSlab.get(i); double 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; double b = (-1) * ( (linesInCenterSlab.get(0).getM() * (thetaLow)) + linesInCenterSlab.get(0) .getB()); slope = m; yInterception = b; String[] result = new String[]{"rm", m + "", b + ""}; notifyObservers(result); } else { double m = thetaLow; double b = (-1) * ((linesInCenterSlab.get(0).getM() * (thetaLow)) + linesInCenterSlab.get(0).getB()); slope = m; yInterception = b; } } /******************************************************************************************************************* * 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; } public Double getSlope() { return slope; } public Double getyInterception() { return yInterception; } }