algorithms-for-computing-li.../LinearRegressionTool/src/main/java/presenter/algorithms/advanced/RepeatedMedianEstimator.java

357 lines
11 KiB
Java
Raw Normal View History

package presenter.algorithms.advanced;
import model.Interval;
import model.Line;
import presenter.Presenter;
import presenter.algorithms.Algorithm;
2017-10-23 15:48:36 +00:00
import presenter.util.FastElementSelector;
import presenter.util.IntersectionCounter;
import presenter.util.RandomSampler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Observable;
/**
* 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<Line> set;
private HashMap<Line, ArrayList<Line>> linePairs;
private HashMap<Line, Double> medianIntersections = new HashMap<>();
private HashMap<Line, ArrayList<Double>> intersectionAbscissas = new HashMap<>();
private Interval interval;
//in der Literatur als L_i, C_i, und R_i bekannt
private ArrayList<Double> countLeftSlab;
private ArrayList<Double> countCenterSlab;
private ArrayList<Double> countRightSlab;
//die Mengen L,C und R
private ArrayList<Line> linesInLeftSlab;
private ArrayList<Line> linesInCenterSlab;
private ArrayList<Line> linesInRightSlab;
private double r;
private int 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;
2017-10-15 13:21:53 +00:00
/**
* Konstruktor
* @param set Liste der Geraden
* @param presenter Presenter (Beobachter)
*/
public RepeatedMedianEstimator(LinkedList<Line> 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<>();
}
2017-10-15 13:21:53 +00:00
/**
* Konstruktor
* @param set Liste der Geraden
*/
public RepeatedMedianEstimator(LinkedList<Line> set) {
this(set, null);
}
/**
2017-10-15 13:21:53 +00:00
* Führt den Algortihmus zur Berechnung des RM-Schätzers durch.
*
2017-10-15 13:21:53 +00:00
* Paper:
* Matousek, Jiri, D. M. Mount und N. S. Netanyahu
* Efficient Randomized Algorithms for the Repeated Median Line Estimator. 1998
* Algorithmica 20.2, S. 136150
*/
public void run() {
System.out.println("=== S T A R T - R M ===");
long start;
long end;
start = System.currentTimeMillis();
while (linesInCenterSlab.size() != 1) {
n = linesInCenterSlab.size();
r = Math.ceil(Math.pow(n, beta));
ArrayList<Line> lines = RandomSampler.run(linesInCenterSlab, r, linesInCenterSlab.size());
2017-10-15 13:21:53 +00:00
//Für jede Gerade aus der Stichprobe wird der Schnittpunkt mit der medianen
//x-Koordinate bestimmt
ArrayList<Double> medianIntersectionAbscissas = new ArrayList<>();
for (Line l : lines) {
Double abscissa = estimateMedianIntersectionAbscissas(l);
medianIntersections.put(l, abscissa);
medianIntersectionAbscissas.add(abscissa);
}
2017-10-15 13:21:53 +00:00
//Rang vom RM-Wert in C
k = Math.max(1, Math.min(set.size(), (Math.ceil(n * 0.5) - linesInLeftSlab.size())));
2017-10-15 13:21:53 +00:00
//berechne k_lo und k_hi
computeSlabBorders();
2017-10-15 13:21:53 +00:00
//Berechne die Elemente mit dem Rang Theta_lo und Theta_hi
thetaLow = FastElementSelector.randomizedSelect(medianIntersectionAbscissas, kLow);
thetaHigh = FastElementSelector.randomizedSelect(medianIntersectionAbscissas, kHigh);
2017-10-15 13:21:53 +00:00
//Für jede Gerade in C wird die Anzahl der Schnittpunkte die im Intervall liegen hochgezählt
countNumberOfIntersectionsAbscissas();
2017-10-15 13:21:53 +00:00
//verkleinere das Intervall
contractIntervals();
}
end = System.currentTimeMillis();
System.out.println("Zeit: "+ ((end-start)/1000));
pepareResult();
}
/**
2017-10-15 13:21:53 +00:00
* Berechnet die mediane x-Koordinate über den Schnittpunkten.
*
* @param sampledLine Stichprobe von Geraden
* @return mediane x-Koordinate über den Schnittpunkten
*/
public Double estimateMedianIntersectionAbscissas(Line sampledLine) {
Integer index = Integer.parseInt(sampledLine.getId());
IntersectionCounter intersectionCounter = new IntersectionCounter();
2017-10-15 13:21:53 +00:00
ArrayList<Double> intersections = intersectionCounter.calculateIntersectionAbscissas(linesInCenterSlab, sampledLine);
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;
return FastElementSelector.randomizedSelect(intersections, accessIndex);
}
/**
2017-10-15 13:21:53 +00:00
* Berechnet die potenziell neuen Intervallgrenzen.
*/
public void computeSlabBorders() {
2017-10-15 13:21:53 +00:00
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))));
}
/**
2017-10-15 13:21:53 +00:00
* Berechnet die Anzahl der Schnittpunkte pro Bereich. Insgesammt gibt es drei Bereiche:
* Im Intervall => (a,b], vor dem Intervall => (a', a], hinter dem Intervall => (b, b'].
*/
public void countNumberOfIntersectionsAbscissas() {
for (Line line : linesInCenterSlab) {
ArrayList<Double> 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++;
}
}
2017-10-23 15:48:36 +00:00
countLeftSlab.set(index, (double) left);
countCenterSlab.set(index, (double) center);
2017-10-23 15:48:36 +00:00
countRightSlab.set(index, (double) right);
}
}
/**
2017-10-15 13:21:53 +00:00
* Verkleinert das aktuelle Intervall. Eines der drei Bereiche wird als neues Intervall gewählt.
* Auf diesem Intervall werden dann in der nächsten Iteration wieder drei Bereiche bestimmt.
*/
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);
}
}
//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 pepareResult() {
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
******************************************************************************************************************/
2017-10-15 13:21:53 +00:00
/**
* @return Anzahl der Geraden
*/
public Integer getN() {
return n;
}
2017-10-15 13:21:53 +00:00
/**
* @param n Anzahl der Geraden
*/
public void setN(Integer n) {
this.n = n;
}
2017-10-15 13:21:53 +00:00
/**
* @param beta Parameter Beta
*/
public void setBeta(Double beta) {
this.beta = beta;
}
2017-10-15 13:21:53 +00:00
/**
* @return Steigung
*/
public Double getSlope() {
return slope;
}
2017-10-15 13:21:53 +00:00
/**
* @return y-Achsenabschnitt
*/
public Double getyInterception() {
return yInterception;
}
2017-10-23 15:48:36 +00:00
/**
* @return temporäres untere Intervallgrenze
*/
public Double getkLow() {
return kLow;
}
/**
* @param kLow temporäres untere Intervallgrenze
*/
public void setkLow(Double kLow) {
this.kLow = kLow;
}
/**
* @return temporäres oberes Intervallgrenze
*/
public Double getkHigh() {
return kHigh;
}
/**
* @param kHigh temporäres oberes Intervallgrenze
*/
public void setkHigh(Double kHigh) {
this.kHigh = kHigh;
}
/**
* @return verteilung der Punkte
*/
public ArrayList<Double> getCountLeftSlab() {
return countLeftSlab;
}
/**
* @return verteilung der Punkte
*/
public ArrayList<Double> getCountCenterSlab() {
return countCenterSlab;
}
/**
* @return verteilung der Punkte
*/
public ArrayList<Double> getCountRightSlab() {
return countRightSlab;
}
}