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

340 lines
11 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package de.wwwu.awolf.presenter.algorithms.advanced;
import de.wwwu.awolf.model.Interval;
import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.model.Point;
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;
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;
import java.util.*;
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;
private List<Line> setOfLines;
private Interval interval;
private Interval original;
//in der Literatur als L_i, C_i, und R_i bekannt
private int countLeftSlab;
private int countCenterSlab;
private int countRightSlab;
//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;
private Flow.Subscriber<? super AlgorithmData> subscriber;
/**
* 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
*/
public Line call() {
n = setOfLines.size();
interval = new Interval(-10000, 10000);
original = new Interval(-10000, 10000);
beta = 0.5;
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++) {
countLeftSlab = 0;
countRightSlab = 0;
countCenterSlab = setOfLines.size();
}
Logging.logInfo("=== S T A R T - R M ===");
long start;
long end;
start = System.currentTimeMillis();
double thetaLow = 0;
double thetaHigh = 0;
while (countCenterSlab > 1) {
n = countCenterSlab;
r = Math.ceil(Math.pow(n, beta));
List<Line> lines = RandomSampler.run(setOfLines, r);
//Für jede Gerade aus der Stichprobe wird der Schnittpunkt mit der medianen
//x-Koordinate bestimmt
List<Double> medianIntersectionAbscissas = new ArrayList<>();
final double lowerBound = thetaLow;
final double upperBound = thetaHigh;
if (!lines.isEmpty()) {
lines.forEach(line -> medianIntersectionAbscissas.add(estimateMedianIntersectionAbscissas(lines, line)));
}
//Rang vom RM-Wert in C
k = Math.max(1, Math.min(n, (Math.ceil(n * 0.5) - countLeftSlab)));
//berechne k_lo und k_hi
computeSlabBorders();
//Berechne die Elemente mit dem Rang Theta_lo und Theta_hi
Collections.sort(medianIntersectionAbscissas);
thetaLow = FastElementSelector.randomizedSelect(medianIntersectionAbscissas, kLow);
thetaHigh = FastElementSelector.randomizedSelect(medianIntersectionAbscissas, kHigh);
//Für jede Gerade in C wird die Anzahl der Schnittpunkte die im Intervall liegen hochgezählt
countNumberOfIntersectionsAbscissas(thetaLow, thetaHigh);
//verkleinere das Intervall
contractIntervals(thetaLow, thetaHigh);
}
end = System.currentTimeMillis();
Logging.logInfo("=== E N D - R M === " + ((end - start) / 1000));
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);
}
/**
* Berechnet die mediane x-Koordinate über den Schnittpunkten.
*
* @param sampledLine Stichprobe von Geraden
* @return mediane x-Koordinate über den Schnittpunkten
*/
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());
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;
else if (i >= intersections.size() && !intersections.isEmpty())
accessIndex = intersections.size() - 1;
else
accessIndex = (int) i;
return FastElementSelector.randomizedSelect(intersections, accessIndex);
}
/**
* Berechnet die potenziell neuen Intervallgrenzen.
*/
public void computeSlabBorders() {
kLow = Math.max(1, Math.floor(((r * k) / (countCenterSlab))
- ((3 * Math.sqrt(r)) * (0.5))));
kHigh = Math.min(r, Math.floor(((r * k) / (countCenterSlab))
+ ((3 * Math.sqrt(r)) * (0.5))));
}
/**
* 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) {
IntersectionComputer instance = IntersectionComputer.getInstance();
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()));
int tmp = new HashSet<>(instance.compute(setOfLines, interval.getLower(), interval.getUpper())).size();
countLeftSlab = intersectionsInLeftSlab.size();
countCenterSlab = intersectionsInCenterSlab.size();
countRightSlab = intersectionsInRightSlab.size();
}
/**
* 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) {
double max = Math.max(countLeftSlab, Math.max(countCenterSlab, countRightSlab));
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
if (newIntervalIsC) {
interval.setLower(lower);
interval.setUpper(upper);
} else if (newIntervalIsL) {
interval.setUpper(lower);
} else if (newIntervalIsR) {
interval.setLower(upper);
}
}
private Line pepareResult(final double thetaLow, final double thetaHigh) {
slope = thetaLow;
List<Double> potentialYInterceptions = new ArrayList<>();
setOfLines.forEach(line -> {
potentialYInterceptions.add(line.getB() - (slope * line.getM()));
});
yInterception = FastElementSelector.randomizedSelect(potentialYInterceptions, Math.floor(potentialYInterceptions.size() * 0.5));
if (this.subscriber != null) {
AlgorithmData data = new AlgorithmData();
data.setAlgorithmType(getType());
data.setType(SubscriberType.ALGORITHM);
data.setLineData(new Line(getSlope(), getyInterception()));
this.subscriber.onNext(data);
}
return new Line(getSlope(), getyInterception());
}
/**
* @return Anzahl der Geraden
*/
public Integer getN() {
return n;
}
/**
* @param n Anzahl der Geraden
*/
public void setN(Integer n) {
this.n = n;
}
/**
* @param beta Parameter Beta
*/
public void setBeta(Double beta) {
this.beta = beta;
}
/**
* @return Steigung
*/
public Double getSlope() {
return slope;
}
/**
* @return y-Achsenabschnitt
*/
public Double getyInterception() {
return yInterception;
}
/**
* @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 int getCountLeftSlab() {
return countLeftSlab;
}
/**
* @return verteilung der Punkte
*/
public int getCountCenterSlab() {
return countCenterSlab;
}
/**
* @return verteilung der Punkte
*/
public int getCountRightSlab() {
return countRightSlab;
}
@Override
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
this.subscriber = subscriber;
}
}