512 lines
13 KiB
Java
512 lines
13 KiB
Java
package Presenter.Algorithms;
|
|
|
|
import Model.Interval;
|
|
import Model.Line;
|
|
import Presenter.*;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.LinkedList;
|
|
import java.util.Observable;
|
|
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 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<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, 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(0);
|
|
countRightSlab.add(0);
|
|
countCenterSlab.add(n - 1);
|
|
intersectionAbscissas.put(set.get(i), new ArrayList<>());
|
|
}
|
|
|
|
linesInLeftSlab = new ArrayList<>();
|
|
linesInCenterSlab = new ArrayList<>(set);
|
|
linesInRightSlab = new ArrayList<>();
|
|
linePairs = new HashMap<>();
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public void run() {
|
|
|
|
while (linesInCenterSlab.size() != 1) {
|
|
n = linesInCenterSlab.size();
|
|
r = Math.ceil(Math.pow(n, beta));
|
|
ArrayList<Line> lines = RandomLineSampler.run(linesInCenterSlab, r, linesInCenterSlab.size());
|
|
|
|
|
|
//For each Sampled Line, compute its median intersection abscissa
|
|
ArrayList<Double> 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()<kHigh || kLow < 0 || kHigh<0 )
|
|
// System.err.print("#medianIntersectionAbscissa: "+medianIntersectionAbscissas.size()+"\t\t klow: "+kLow+" kHigh: "+kHigh+"\n\n");
|
|
|
|
//Employ fast selection algorithm to determine the Elements Theta_lo and Theta_hi
|
|
thetaLow = randomizedSelect(medianIntersectionAbscissas, kLow);
|
|
thetaHigh = randomizedSelect(medianIntersectionAbscissas, kHigh);
|
|
|
|
//For each dual Line in C count the number of intersection abscissas that lie
|
|
//in each of the intervals.
|
|
countNumberOfIntersectionsAbscissas();
|
|
|
|
//Based on this 3 counts, determine which of the subintervals contains the repeated median
|
|
//and contract to this subiinterval.
|
|
contractIntervals();
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param set
|
|
* @param r
|
|
* @return
|
|
*/
|
|
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, linesInCenterSlab.size())));
|
|
}
|
|
|
|
return sampledLines;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param sampledLine
|
|
* @return
|
|
*/
|
|
public Double estimateMedianIntersectionAbscissas(Line sampledLine) {
|
|
|
|
Integer index = Integer.parseInt(sampledLine.getId());
|
|
ArrayList<Double> 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)));
|
|
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);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
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))
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param a
|
|
* @param i
|
|
* @return
|
|
*/
|
|
public Double randomizedSelect(ArrayList<Double> a, double i) {
|
|
int start = 0;
|
|
int end = a.size()-1;
|
|
if (i >= end+1){
|
|
return a.get(end);
|
|
}
|
|
|
|
while(true){
|
|
if(start == end){
|
|
return a.get(start);
|
|
}
|
|
int q = randomizedPartition(a, start, end);
|
|
int k = q-start+1;
|
|
|
|
if(i == k){
|
|
return a.get(q);
|
|
}
|
|
else{
|
|
if(i <k){
|
|
end = q -1;
|
|
}else{
|
|
i = i - k;
|
|
start = q + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param a
|
|
* @param start
|
|
* @param end
|
|
* @return
|
|
*/
|
|
public int randomizedPartition(ArrayList<Double> a, int start, int end) {
|
|
int i = 0;
|
|
Random random = new Random(System.currentTimeMillis());
|
|
|
|
//alternative: ThreadLocalRandom.current()
|
|
if(start < end){
|
|
i = start + random.nextInt(end-start);
|
|
}else{
|
|
i = end + random.nextInt(start-end);
|
|
}
|
|
|
|
Collections.swap(a, end, i);
|
|
return partition(a, start, end);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param a
|
|
* @param start
|
|
* @param end
|
|
* @return
|
|
*/
|
|
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-1; j++) {
|
|
if (a.get(j) <= x) {
|
|
i++;
|
|
Collections.swap(a, i, j);
|
|
}
|
|
}
|
|
Collections.swap(a, i+1, end);
|
|
return i+1;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
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++;
|
|
}
|
|
}
|
|
|
|
//System.out.println("Linie: "+line.getId()+"\tLeft: "+left+"\t Center: "+center+"\t Right: "+right);
|
|
countLeftSlab.set(index, left);
|
|
countCenterSlab.set(index, center);
|
|
countRightSlab.set(index, right);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public void contractIntervals() {
|
|
for (int i = 0; i < linesInCenterSlab.size(); i++) {
|
|
|
|
int left = countLeftSlab.get(i);
|
|
int center = countCenterSlab.get(i);
|
|
int right = countRightSlab.get(i);
|
|
|
|
int 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 * (-1);
|
|
double b = (
|
|
(linesInCenterSlab.get(0).getM() * (thetaLow)) + linesInCenterSlab.get(0)
|
|
.getB());
|
|
|
|
String[] result = new String[]{"rm", m+"", b+""};
|
|
notifyObservers(result);
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************************************************
|
|
* Getter und Setter Methoden
|
|
******************************************************************************************************************/
|
|
public LinkedList<Line> getSet() {
|
|
return set;
|
|
}
|
|
|
|
public void setSet(LinkedList<Line> set) {
|
|
this.set = set;
|
|
}
|
|
|
|
public HashMap<Line, ArrayList<Line>> getLinePairs() {
|
|
return linePairs;
|
|
}
|
|
|
|
public void setLinePairs(HashMap<Line, ArrayList<Line>> linePairs) {
|
|
this.linePairs = linePairs;
|
|
}
|
|
|
|
public HashMap<Line, Double> getMedianIntersections() {
|
|
return medianIntersections;
|
|
}
|
|
|
|
public void setMedianIntersections(HashMap<Line, Double> medianIntersections) {
|
|
this.medianIntersections = medianIntersections;
|
|
}
|
|
|
|
public HashMap<Line, ArrayList<Double>> getIntersectionAbscissas() {
|
|
return intersectionAbscissas;
|
|
}
|
|
|
|
public void setIntersectionAbscissas(
|
|
HashMap<Line, ArrayList<Double>> intersectionAbscissas) {
|
|
this.intersectionAbscissas = intersectionAbscissas;
|
|
}
|
|
|
|
public Interval getInterval() {
|
|
return interval;
|
|
}
|
|
|
|
public void setInterval(Interval interval) {
|
|
this.interval = interval;
|
|
}
|
|
|
|
public ArrayList<Integer> getCountLeftSlab() {
|
|
return countLeftSlab;
|
|
}
|
|
|
|
public void setCountLeftSlab(ArrayList<Integer> countLeftSlab) {
|
|
this.countLeftSlab = countLeftSlab;
|
|
}
|
|
|
|
public ArrayList<Integer> getCountCenterSlab() {
|
|
return countCenterSlab;
|
|
}
|
|
|
|
public void setCountCenterSlab(ArrayList<Integer> countCenterSlab) {
|
|
this.countCenterSlab = countCenterSlab;
|
|
}
|
|
|
|
public ArrayList<Integer> getCountRightSlab() {
|
|
return countRightSlab;
|
|
}
|
|
|
|
public void setCountRightSlab(ArrayList<Integer> countRightSlab) {
|
|
this.countRightSlab = countRightSlab;
|
|
}
|
|
|
|
public ArrayList<Line> getLinesInLeftSlab() {
|
|
return linesInLeftSlab;
|
|
}
|
|
|
|
public void setLinesInLeftSlab(ArrayList<Line> linesInLeftSlab) {
|
|
this.linesInLeftSlab = linesInLeftSlab;
|
|
}
|
|
|
|
public ArrayList<Line> getLinesInCenterSlab() {
|
|
return linesInCenterSlab;
|
|
}
|
|
|
|
public void setLinesInCenterSlab(ArrayList<Line> linesInCenterSlab) {
|
|
this.linesInCenterSlab = linesInCenterSlab;
|
|
}
|
|
|
|
public ArrayList<Line> getLinesInRightSlab() {
|
|
return linesInRightSlab;
|
|
}
|
|
|
|
public void setLinesInRightSlab(ArrayList<Line> 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;
|
|
}
|
|
}
|
|
|
|
|