244 lines
7.0 KiB
Java
244 lines
7.0 KiB
Java
package Presenter.Algorithms;
|
|
|
|
import Model.Line;
|
|
import Model.Slab;
|
|
import Presenter.InversionCounter;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.LinkedList;
|
|
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 implements Algorithm {
|
|
|
|
private LinkedList<Line> set;
|
|
private HashMap<Line, ArrayList<Line>> linePairs;
|
|
private Slab interval;
|
|
|
|
//in der Literatur als L_i, C_i, und R_i bekannt
|
|
private ArrayList<Integer> countLeftSlab;
|
|
private ArrayList<Integer> countCenterSlab;
|
|
private ArrayList<Integer> countRightSlab;
|
|
|
|
//die Mengen L,C und R
|
|
private ArrayList<Line> linesInLeftSlab;
|
|
private ArrayList<Line> linesInCenterSlab;
|
|
private ArrayList<Line> 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<Line> set) {
|
|
this.set = set;
|
|
interval = new Slab(-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);
|
|
}
|
|
|
|
linesInLeftSlab = new ArrayList<>();
|
|
linesInCenterSlab = new ArrayList<>(set);
|
|
linesInRightSlab = new ArrayList<>();
|
|
linePairs = new HashMap<>();
|
|
}
|
|
|
|
|
|
public void run() {
|
|
|
|
while (linesInCenterSlab.size() != 1) {
|
|
r = Math.floor(Math.pow(n, beta));
|
|
ArrayList<Line> lines = sampleLines(linesInCenterSlab, r);
|
|
|
|
InversionCounter invCounter = new InversionCounter();
|
|
invCounter.run(lines, interval);
|
|
|
|
HashMap<Line, ArrayList<Line>> tmpMap;
|
|
tmpMap = invCounter.getIntersectionAbscissas();
|
|
linePairs.putAll(tmpMap);
|
|
if (tmpMap.size() > 0){
|
|
ArrayList<Double> medianIntersections = new ArrayList<>();
|
|
for (Line l : lines) {
|
|
medianIntersections.add(estimateMedianIntersectionAbscissas(l));
|
|
}
|
|
|
|
k = (Math.floor(n * 0.5) - linesInLeftSlab.size());
|
|
computeSlabBorders();
|
|
thetaLow = randomizedSelect(medianIntersections, 0, medianIntersections.size() - 1, kLow);
|
|
thetaHigh = randomizedSelect(medianIntersections, 0, medianIntersections.size() - 1, kHigh);
|
|
|
|
for (Line l : linesInCenterSlab) {
|
|
countNumberOfIntersectionsAbscissas(l);
|
|
}
|
|
|
|
contractIntervals();
|
|
}
|
|
}
|
|
|
|
System.out.println(
|
|
"Ergebnis: " + linesInCenterSlab.get(0).getM() + " * x + " + linesInCenterSlab.get(0)
|
|
.getB());
|
|
}
|
|
|
|
|
|
public void computeSlabBorders() {
|
|
kLow = Math
|
|
.max(1, Math.ceil(((r * k) / (linesInCenterSlab.size())) - ((3 * Math.sqrt(r)) / (2))));
|
|
kHigh = Math
|
|
.min(r, Math.ceil(((r * k) / (linesInCenterSlab.size())) + ((3 * Math.sqrt(r)) / (2))));
|
|
}
|
|
|
|
public ArrayList<Line> sampleLines(ArrayList<Line> set, Double r) {
|
|
|
|
ArrayList<Line> sampledLines = new ArrayList<>();
|
|
|
|
for (int i = 0; i < r; i++) {
|
|
sampledLines.add(set.get(ThreadLocalRandom.current().nextInt(0, n)));
|
|
}
|
|
|
|
return sampledLines;
|
|
}
|
|
|
|
|
|
public Double randomizedSelect(ArrayList<Double> a, int start, int end, double i) {
|
|
if (start == end) {
|
|
return a.get(start);
|
|
}
|
|
int q = randomizedPartition(a, start, end);
|
|
int tmpPivot = q - start + 1;
|
|
|
|
if (i == tmpPivot) {
|
|
return a.get(q);
|
|
} else if (i < tmpPivot) {
|
|
return randomizedSelect(a, start, q - 1, i);
|
|
} else {
|
|
return randomizedSelect(a, q + 1, end, i - tmpPivot);
|
|
}
|
|
}
|
|
|
|
public int randomizedPartition(ArrayList<Double> a, int start, int end) {
|
|
int delta = Math.abs(end - start);
|
|
int i = start + ThreadLocalRandom.current().nextInt(0, delta);
|
|
Collections.swap(a, end, i);
|
|
return partition(a, start, end);
|
|
}
|
|
|
|
public int partition(ArrayList<Double> a, int start, int end) {
|
|
Double x = a.get(end);
|
|
int i = start - 1;
|
|
for (int j = start; j < end; j++) {
|
|
if (a.get(j) <= x) {
|
|
i++;
|
|
Collections.swap(a, i, j);
|
|
}
|
|
}
|
|
Collections.swap(a, i + 1, end);
|
|
return i + 1;
|
|
}
|
|
|
|
|
|
public void countNumberOfIntersectionsAbscissas(Line sampledLine) {
|
|
|
|
if (linePairs.get(sampledLine) != null){
|
|
double intersection;
|
|
Integer index = Integer.parseInt(sampledLine.getId());
|
|
|
|
for (Line line : linePairs.get(sampledLine)) {
|
|
intersection = (line.getB() - sampledLine.getB()) / (sampledLine.getM() - line.getM());
|
|
|
|
int tmpVal;
|
|
if (intersection <= thetaLow) {
|
|
tmpVal = countLeftSlab.get(index) + 1;
|
|
countLeftSlab.set(index, tmpVal);
|
|
tmpVal = countCenterSlab.get(index) - 1;
|
|
countCenterSlab.set(index, tmpVal);
|
|
} else if (intersection > thetaHigh) {
|
|
tmpVal = countRightSlab.get(index) + 1;
|
|
countRightSlab.set(index, tmpVal);
|
|
tmpVal = countCenterSlab.get(index) - 1;
|
|
countCenterSlab.set(index, tmpVal);
|
|
}
|
|
|
|
countCenterSlab
|
|
.set(index, Math.abs((n - 1) - (countLeftSlab.get(index) + countRightSlab.get(index))));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public Double estimateMedianIntersectionAbscissas(Line sampledLine) {
|
|
|
|
Integer index = Integer.parseInt(sampledLine.getId());
|
|
ArrayList<Double> intersections = new ArrayList<>();
|
|
double intersection;
|
|
|
|
for (Line line : linePairs.get(sampledLine)) {
|
|
if (line != sampledLine){
|
|
intersection = (line.getB() - sampledLine.getB()) / (sampledLine.getM() - line.getM());
|
|
intersections.add(intersection);
|
|
}
|
|
}
|
|
|
|
Collections.sort(intersections);
|
|
double ki = Math.floor((n - 1) / 2) - countLeftSlab.get(index);
|
|
int accessIndex = ((int) Math.floor((Math.sqrt(n) * ki) / countCenterSlab.get(index)))-1;
|
|
System.out.println(accessIndex);
|
|
|
|
return intersections.get(accessIndex);
|
|
}
|
|
|
|
|
|
public void contractIntervals() {
|
|
if (linesInLeftSlab.size() < Math.floor(n / 2) && Math.floor(n / 2) <= (linesInLeftSlab.size()
|
|
+ linesInCenterSlab.size())) {
|
|
for (int i = 0; i < linesInCenterSlab.size(); i++) {
|
|
int maxVal = Math
|
|
.max(countLeftSlab.get(i), Math.max(countCenterSlab.get(i), countRightSlab.get(i)));
|
|
if (countLeftSlab.get(i) == maxVal) {
|
|
linesInLeftSlab.add(linesInCenterSlab.get(i));
|
|
linesInCenterSlab.remove(i);
|
|
}
|
|
|
|
if (countRightSlab.get(i) == maxVal) {
|
|
linesInRightSlab.add(linesInCenterSlab.get(i));
|
|
linesInCenterSlab.remove(i);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
countLeftSlab.set(i,0);
|
|
countRightSlab.set(i,0);
|
|
countCenterSlab.set(i,n - 1);
|
|
}
|
|
|
|
interval.setLower(thetaLow - 0.01);
|
|
interval.setUpper(thetaHigh);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|