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

340 lines
11 KiB
Java
Raw Normal View History

2020-03-21 00:37:09 +00:00
package de.wwwu.awolf.presenter.algorithms.advanced;
import de.wwwu.awolf.model.Interval;
import de.wwwu.awolf.model.Line;
2020-03-23 06:58:40 +00:00
import de.wwwu.awolf.model.Point;
2020-03-21 00:37:09 +00:00
import de.wwwu.awolf.model.communication.AlgorithmData;
import de.wwwu.awolf.model.communication.Data;
import de.wwwu.awolf.model.communication.SubscriberType;
import de.wwwu.awolf.presenter.AbstractPresenter;
2020-03-21 00:37:09 +00:00
import de.wwwu.awolf.presenter.algorithms.Algorithm;
import de.wwwu.awolf.presenter.util.FastElementSelector;
import de.wwwu.awolf.presenter.util.IntersectionComputer;
import de.wwwu.awolf.presenter.util.Logging;
import de.wwwu.awolf.presenter.util.RandomSampler;
2020-03-23 06:58:40 +00:00
import java.util.*;
2020-03-21 00:37:09 +00:00
import java.util.concurrent.Flow;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
*
* @Author: Armin Wolf
* @Email: a_wolf28@uni-muenster.de
* @Date: 28.05.2017.
*/
public class RepeatedMedianEstimator implements Algorithm {
private static final Algorithm.Type type = Type.RM;
private AbstractPresenter presenter;
2020-03-23 06:58:40 +00:00
private List<Line> setOfLines;
private Interval interval;
2020-03-23 06:58:40 +00:00
private Interval original;
//in der Literatur als L_i, C_i, und R_i bekannt
2020-03-23 06:58:40 +00:00
private int countLeftSlab;
private int countCenterSlab;
private int countRightSlab;
2020-03-23 06:58:40 +00:00
//in der Literatur als L_i, C_i, und R_i bekannt
private Set<Point> intersectionsInLeftSlab;
private Set<Point> intersectionsInCenterSlab;
private Set<Point> intersectionsInRightSlab;
private double r;
private int n;
private double k;
private double kLow;
private double kHigh;
private double beta;
private double slope;
private double yInterception;
2020-03-21 00:37:09 +00:00
private Flow.Subscriber<? super AlgorithmData> subscriber;
2017-10-15 13:21:53 +00:00
/**
* Führt den Algortihmus zur Berechnung des RM-Schätzers durch.
* <p>
* 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
2017-10-15 13:21:53 +00:00
*/
public Line call() {
2020-03-23 06:58:40 +00:00
n = setOfLines.size();
interval = new Interval(-10000, 10000);
original = new Interval(-10000, 10000);
beta = 0.5;
2020-03-23 06:58:40 +00:00
intersectionsInLeftSlab = new HashSet<>();
intersectionsInCenterSlab = new HashSet<>();
intersectionsInRightSlab = new HashSet<>();
intersectionsInLeftSlab.add(new Point(0d, 0d));
intersectionsInCenterSlab.add(new Point(0d, 0d));
intersectionsInCenterSlab.add(new Point(0d, 0d));
for (int i = 0; i < n; i++) {
2020-03-23 06:58:40 +00:00
countLeftSlab = 0;
countRightSlab = 0;
countCenterSlab = setOfLines.size();
}
2020-03-21 00:37:09 +00:00
Logging.logInfo("=== S T A R T - R M ===");
long start;
long end;
start = System.currentTimeMillis();
2020-03-23 06:58:40 +00:00
double thetaLow = 0;
double thetaHigh = 0;
2020-03-23 06:58:40 +00:00
while (countCenterSlab > 1) {
n = countCenterSlab;
r = Math.ceil(Math.pow(n, beta));
2020-03-23 06:58:40 +00:00
List<Line> lines = RandomSampler.run(setOfLines, r);
2017-10-15 13:21:53 +00:00
//Für jede Gerade aus der Stichprobe wird der Schnittpunkt mit der medianen
//x-Koordinate bestimmt
2020-03-21 00:37:09 +00:00
List<Double> medianIntersectionAbscissas = new ArrayList<>();
2020-03-23 06:58:40 +00:00
final double lowerBound = thetaLow;
final double upperBound = thetaHigh;
if (!lines.isEmpty()) {
lines.forEach(line -> medianIntersectionAbscissas.add(estimateMedianIntersectionAbscissas(lines, line)));
}
2017-10-15 13:21:53 +00:00
//Rang vom RM-Wert in C
2020-03-23 06:58:40 +00:00
k = Math.max(1, Math.min(n, (Math.ceil(n * 0.5) - countLeftSlab)));
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
2020-03-23 06:58:40 +00:00
Collections.sort(medianIntersectionAbscissas);
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
2020-03-23 06:58:40 +00:00
countNumberOfIntersectionsAbscissas(thetaLow, thetaHigh);
2017-10-15 13:21:53 +00:00
//verkleinere das Intervall
2020-03-23 06:58:40 +00:00
contractIntervals(thetaLow, thetaHigh);
}
2020-03-23 06:58:40 +00:00
end = System.currentTimeMillis();
2020-03-23 06:58:40 +00:00
Logging.logInfo("=== E N D - R M === " + ((end - start) / 1000));
2020-03-23 06:58:40 +00:00
return pepareResult(thetaLow, thetaHigh);
}
@Override
public void setInput(Set<Line> lines) {
this.setOfLines = new LinkedList<>(lines);
this.n = setOfLines.size();
}
@Override
public Type getType() {
return type;
}
@Override
public void setPresenter(AbstractPresenter presenter) {
this.presenter = presenter;
subscribe(presenter);
}
/**
2017-10-15 13:21:53 +00:00
* Berechnet die mediane x-Koordinate über den Schnittpunkten.
*
* @param sampledLine Stichprobe von Geraden
2020-03-20 17:08:18 +00:00
* @return mediane x-Koordinate über den Schnittpunkten
*/
2020-03-23 06:58:40 +00:00
public Double estimateMedianIntersectionAbscissas(List<Line> lines, Line sampledLine) {
List<Double> intersections = IntersectionComputer.getInstance().calculateIntersectionAbscissas(lines, sampledLine, original.getLower(), original.getUpper());
List<Double> left = IntersectionComputer.getInstance().calculateIntersectionAbscissas(lines, sampledLine, original.getLower(), interval.getLower());
List<Double> center = IntersectionComputer.getInstance().calculateIntersectionAbscissas(lines, sampledLine, interval.getLower(), interval.getUpper());
2020-03-23 06:58:40 +00:00
2020-03-23 06:58:40 +00:00
double ki = Math.ceil((n - 1) * 0.5) - left.size();
double i = (Math.ceil((Math.sqrt(n) * ki) / center.size()));
int accessIndex;
if (i < 0)
accessIndex = 0;
2020-03-23 06:58:40 +00:00
else if (i >= intersections.size() && !intersections.isEmpty())
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() {
2020-03-23 06:58:40 +00:00
kLow = Math.max(1, Math.floor(((r * k) / (countCenterSlab))
2020-03-21 00:37:09 +00:00
- ((3 * Math.sqrt(r)) * (0.5))));
2020-03-23 06:58:40 +00:00
kHigh = Math.min(r, Math.floor(((r * k) / (countCenterSlab))
2020-03-21 00:37:09 +00:00
+ ((3 * Math.sqrt(r)) * (0.5))));
}
/**
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(final double lower, final double upper) {
2020-03-23 06:58:40 +00:00
IntersectionComputer instance = IntersectionComputer.getInstance();
2020-03-23 06:58:40 +00:00
intersectionsInLeftSlab = new HashSet<>(instance.compute(setOfLines, interval.getLower(), lower));
intersectionsInCenterSlab = new HashSet<>(instance.compute(setOfLines, lower, upper));
intersectionsInRightSlab = new HashSet<>(instance.compute(setOfLines, upper, interval.getUpper()));
2020-03-23 06:58:40 +00:00
int tmp = new HashSet<>(instance.compute(setOfLines, interval.getLower(), interval.getUpper())).size();
2020-03-23 06:58:40 +00:00
countLeftSlab = intersectionsInLeftSlab.size();
countCenterSlab = intersectionsInCenterSlab.size();
countRightSlab = intersectionsInRightSlab.size();
}
/**
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(final double lower, final double upper) {
2020-03-23 06:58:40 +00:00
double max = Math.max(countLeftSlab, Math.max(countCenterSlab, countRightSlab));
2020-03-23 06:58:40 +00:00
boolean newIntervalIsC = countLeftSlab < Math.ceil(n * 0.5) && Math.ceil(n * 0.5) <= countLeftSlab + countCenterSlab;
boolean newIntervalIsL = Math.ceil(n * 0.5) <= countLeftSlab;
boolean newIntervalIsR = countLeftSlab + countCenterSlab < Math.ceil(n * 0.5) && Math.ceil(n * 0.5) <= (countLeftSlab + countCenterSlab + countRightSlab);
//wähle C als C
2020-03-23 06:58:40 +00:00
if (newIntervalIsC) {
interval.setLower(lower);
interval.setUpper(upper);
} else if (newIntervalIsL) {
interval.setUpper(lower);
} else if (newIntervalIsR) {
interval.setLower(upper);
}
}
2020-03-23 06:58:40 +00:00
private Line pepareResult(final double thetaLow, final double thetaHigh) {
slope = thetaLow;
List<Double> potentialYInterceptions = new ArrayList<>();
2020-03-23 06:58:40 +00:00
setOfLines.forEach(line -> {
potentialYInterceptions.add(line.getB() - (slope * line.getM()));
});
yInterception = FastElementSelector.randomizedSelect(potentialYInterceptions, Math.floor(potentialYInterceptions.size() * 0.5));
2020-03-23 06:58:40 +00:00
if (this.subscriber != null) {
2020-03-21 00:37:09 +00:00
AlgorithmData data = new AlgorithmData();
data.setAlgorithmType(getType());
data.setType(SubscriberType.ALGORITHM);
2020-03-23 06:58:40 +00:00
data.setLineData(new Line(getSlope(), getyInterception()));
2020-03-21 00:37:09 +00:00
this.subscriber.onNext(data);
}
2020-03-21 19:54:03 +00:00
return new Line(getSlope(), getyInterception());
}
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;
}
/**
2020-03-20 17:08:18 +00:00
* @return verteilung der Punkte
2017-10-23 15:48:36 +00:00
*/
2020-03-23 06:58:40 +00:00
public int getCountLeftSlab() {
2017-10-23 15:48:36 +00:00
return countLeftSlab;
}
/**
* @return verteilung der Punkte
*/
2020-03-23 06:58:40 +00:00
public int getCountCenterSlab() {
2017-10-23 15:48:36 +00:00
return countCenterSlab;
}
/**
* @return verteilung der Punkte
*/
2020-03-23 06:58:40 +00:00
public int getCountRightSlab() {
2017-10-23 15:48:36 +00:00
return countRightSlab;
}
2020-03-21 00:37:09 +00:00
@Override
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
this.subscriber = subscriber;
}
}