fixed the issue with rm estimator

This commit is contained in:
Armin Wolf 2020-03-23 07:58:40 +01:00
parent 2a003fee9a
commit bef956bf4c
32 changed files with 152488 additions and 6054 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,8 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>wwu</groupId>
<artifactId>Masterarbeit</artifactId>
<groupId>de.wwu.awolf</groupId>
<artifactId>masterarbeit</artifactId>
<version>1.0</version>
<build>
@ -13,13 +13,13 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<!-- Maven Assembly Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -49,21 +49,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.googlecode.mavennatives</groupId>
<artifactId>maven-nativedependencies-plugin</artifactId>
<version>0.0.7</version>
<executions>
<execution>
<id>unpacknatives</id>
<phase>generate-resources</phase>
<goals>
<goal>copy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
@ -88,20 +73,6 @@
<version>4.12</version>
</dependency>
<!-- OpenCSV-->
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>3.9</version>
</dependency>
<!-- JTattoo Look and Feel -->
<dependency>
<groupId>com.jtattoo</groupId>
<artifactId>JTattoo</artifactId>
<version>1.6.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
@ -109,12 +80,6 @@
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.openpnp</groupId>
<artifactId>opencv</artifactId>
<version>3.2.0-1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
@ -122,13 +87,16 @@
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
</dependencies>
</project>

View File

@ -51,10 +51,26 @@ public class Line {
this.m = m;
this.b = b;
this.x1 = MIN;
this.y1 = (MIN * m) + b;
this.x2 = MAX * 0.5;
this.y2 = ((MAX * 0.5) * m) + b;
this.x1 = calculateX1(MIN);
this.y1 = calculateY1(MIN);
this.x2 = calculateX2(MAX * 0.5);
this.y2 = calculateY2(MAX * 0.5);
}
private Double calculateX1(Double min) {
return (double) min;
}
private Double calculateY1(Double min) {
return (min * m) + b;
}
private Double calculateX2(Double max) {
return (double) max;
}
private Double calculateY2(Double max) {
return (max * m) + b;
}
/**
@ -188,4 +204,74 @@ public class Line {
public String toString() {
return "Line m: " + this.getM() + ", b: " + this.getB();
}
public Point intersect(Line line) {
double x = (line.b - this.b) / (this.m - line.m);
double y = this.m * x + this.b;
return new Point(x, y);
}
// Given three colinear points p, q, r, the function checks if
// point q lies on line segment 'pr'
public boolean onSegment(Point p, Point q, Point r) {
if (q.getX() <= Math.max(p.getX(), r.getX()) && q.getX() >= Math.min(p.getX(), r.getX()) &&
q.getY() <= Math.max(p.getY(), r.getY()) && q.getY() >= Math.min(p.getY(), r.getY()))
return true;
return false;
}
// To find orientation of ordered triplet (p, q, r).
// The function returns following values
// 0 --> p, q and r are colinear
// 1 --> Clockwise
// 2 --> Counterclockwise
public int orientation(Point p, Point q, Point r) {
// See https://www.geeksforgeeks.org/orientation-3-ordered-points/
// for details of below formula.
double val = (q.getY() - p.getY()) * (r.getX() - q.getX()) -
(q.getX() - p.getX()) * (r.getY() - q.getY());
if (val == 0) return 0; // colinear
return (val > 0) ? 1 : 2; // clock or counterclock wise
}
// The main function that returns true if line segment 'p1q1'
// and 'p2q2' intersect.
// Line A: y = mx + b -->
public boolean doIntersect(Line line, double lower, double upper) {
//this
Point p1 = new Point(calculateX1(lower), calculateY1(lower));
Point q1 = new Point(calculateX2(upper), calculateY2(upper));
Point p2 = new Point(line.calculateX1(lower), line.calculateY1(lower));
Point q2 = new Point(line.calculateX2(upper), line.calculateY2(upper));
// Find the four orientations needed for general and
// special cases
int o1 = orientation(p1, q1, p2);
int o2 = orientation(p1, q1, q2);
int o3 = orientation(p2, q2, p1);
int o4 = orientation(p2, q2, q1);
// General case
if (o1 != o2 && o3 != o4)
return true;
// Special Cases
// p1, q1 and p2 are colinear and p2 lies on segment p1q1
if (o1 == 0 && onSegment(p1, p2, q1)) return true;
// p1, q1 and q2 are colinear and q2 lies on segment p1q1
if (o2 == 0 && onSegment(p1, q2, q1)) return true;
// p2, q2 and p1 are colinear and p1 lies on segment p2q2
if (o3 == 0 && onSegment(p2, p1, q2)) return true;
// p2, q2 and q1 are colinear and q1 lies on segment p2q2
if (o4 == 0 && onSegment(p2, q1, q2)) return true;
return false; // Doesn't fall in any of the above cases
}
}

View File

@ -13,7 +13,6 @@ import java.util.List;
*/
public class LineModel {
private List<Point> nodes;
private List<Line> lines;
private Double xMinimum;
private Double xMaximum;
@ -24,7 +23,6 @@ public class LineModel {
* Konstruktor
*/
public LineModel() {
nodes = new ArrayList<>();
lines = new LinkedList<>();
xMinimum = Double.MAX_VALUE;
@ -34,14 +32,6 @@ public class LineModel {
}
/**
* Fügt einen Schnittpunkt zum Modell hinzu
*
* @param node Schnittpunkt
*/
public void addNode(Point node) {
this.nodes.add(node);
}
/**
* Fügt eine Gerade zu dem Modell hinzu
@ -52,19 +42,6 @@ public class LineModel {
this.lines.add(line);
}
/**
* @return Liste der Schnittpunkte
*/
public List<Point> getNodes() {
return nodes;
}
/**
* @param nodes Liste der Schnittpunkte
*/
public void setNodes(List<Point> nodes) {
this.nodes = nodes;
}
/**
* @return Liste der Geraden

View File

@ -114,4 +114,8 @@ public class Point implements Comparable<Point> {
public void setId(String id) {
this.id = id;
}
}

View File

@ -90,47 +90,6 @@ public abstract class AbstractPresenter implements Flow.Subscriber<Data> {
}
/**
* Startet das parallele Berechnen der Schnittpunkte der Geraden die im Modell enthalten sind.
*/
private void startIntersectionCalculation() {
getExecutor().submit(() -> {
getModel().resetRanges();
IntersectionComputer intersectionComputer = new IntersectionComputer(getModel().getLines());
getModel().setNodes(intersectionComputer.compute());
getModel().setxMaximum(intersectionComputer.getxMaximum());
getModel().setxMinimum(intersectionComputer.getxMinimum());
getModel().setyMaximum(intersectionComputer.getyMaximum());
getModel().setyMinimum(intersectionComputer.getyMinimum());
});
}
/**
* Wrapper Methode die das berechnen der Schnittpunkte anstößt und die Ergebnisse(Anzahl der Schnittpunkte)
* visuell darstellt.
*/
protected void computeIntersections() {
getExecutor().submit(() -> {
long start, end;
start = System.currentTimeMillis();
startIntersectionCalculation();
end = System.currentTimeMillis();
Logging.logInfo("Computing intersections took " + (end - start) / 1000 + "ms");
});
//darstellung der Ergebnisse
SwingUtilities.invokeLater(() -> {
getView().enableFunctionality();
getView().getProgressDialog().dispose();
});
Logging.logInfo("Informationen zu dem aktuellen Modell");
Logging.logInfo("Anzahl der Geraden: " + getModel().getLines().size() + ".");
Logging.logInfo("Anzahl der Schnittpunkte: " + getModel().getNodes().size() + ".");
Logging.logInfo("Import war Erfolgreich!");
}
/**
* @return das zu grunde legende Modell
*/

View File

@ -63,10 +63,6 @@ public class Presenter extends AbstractPresenter {
}
public void visualizeDualLines() {
getView().createDualityDialog();
}
/***************************************************************************************************************************
* Ausführung der Algorithmen
***************************************************************************************************************************/
@ -81,7 +77,7 @@ public class Presenter extends AbstractPresenter {
//Parameter für den Algortihmus
Double constant = Double.parseDouble(input[0]);
double error = Double.parseDouble(input[1]);
LeastMedianOfSquaresEstimator lms = new LeastMedianOfSquaresEstimator(getModel().getLines(), getModel().getNodes(), this);
LeastMedianOfSquaresEstimator lms = new LeastMedianOfSquaresEstimator(getModel().getLines(), this);
//setzen der Parameter
lms.setConstant(constant);
lms.setQuantileError(error);
@ -114,7 +110,7 @@ public class Presenter extends AbstractPresenter {
*/
public void calculateTS(String input) {
if (input != null) {
TheilSenEstimator ts = new TheilSenEstimator(getModel().getLines(), getModel().getNodes(), this);
TheilSenEstimator ts = new TheilSenEstimator(getModel().getLines(), this);
//Presenter soll die Klasse überwachen
getExecutor().submit(ts);
}
@ -131,12 +127,10 @@ public class Presenter extends AbstractPresenter {
*/
public void startImport(File file) {
List<Line> data = getDataProvider().getData(file);
if (data != null) {
//Berechnung der Schnittpunkte und vis. der Ergebnisse (anz. Geraden, anz. Schnittpunkte)
getModel().setLines(data);
computeIntersections();
}
//Berechnung der Schnittpunkte und vis. der Ergebnisse (anz. Geraden, anz. Schnittpunkte)
getModel().setLines(data);
getView().enableFunctionality();
Logging.logInfo("Import successfully! " + Thread.currentThread().getName());
}
/**
@ -166,8 +160,8 @@ public class Presenter extends AbstractPresenter {
public void generateDataset(int n, DataProvider.DataType type) {
List<Line> data = getDataProvider().getData(type, n);
getModel().setLines(data);
computeIntersections();
getView().enableFunctionality();
Logging.logInfo("Generated successfully!" + Thread.currentThread().getName());
}
/**

View File

@ -8,7 +8,7 @@ import de.wwwu.awolf.model.communication.Data;
import de.wwwu.awolf.model.communication.SubscriberType;
import de.wwwu.awolf.presenter.Presenter;
import de.wwwu.awolf.presenter.algorithms.Algorithm;
import de.wwwu.awolf.presenter.util.IntersectionCounter;
import de.wwwu.awolf.presenter.util.IntersectionComputer;
import de.wwwu.awolf.presenter.util.Logging;
import java.util.*;
@ -23,9 +23,7 @@ import java.util.concurrent.Flow;
*/
public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<Data> {
private List<Line> set;
private List<Point> intersections;
private IntersectionCounter invCounter = new IntersectionCounter();
private List<Line> setOfLines;
private int n;
private double quantileError;
private int kPlus;
@ -45,16 +43,13 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
/**
* Konstruktor
*
* @param set Liste der Geraden
* @param intersections Liste der Schnittpunkte
* @param setOfLines Liste der Geraden
* @param presenter Presenter (Beobachter)
*/
public LeastMedianOfSquaresEstimator(List<Line> set, List<Point> intersections,
Presenter presenter) {
this.set = set;
this.intersections = intersections;
public LeastMedianOfSquaresEstimator(List<Line> setOfLines, Presenter presenter) {
this.setOfLines = setOfLines;
n = set.size();
n = setOfLines.size();
double qPlus = 0.5;
quantileError = 0.1;
double qMinus = qPlus * (1 - quantileError);
@ -66,11 +61,10 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
/**
* Konstruktor
*
* @param set Liste der Geraden
* @param intersections Liste der Schnittpunkte
* @param setOfLines Liste der Geraden
*/
public LeastMedianOfSquaresEstimator(List<Line> set, List<Point> intersections) {
this(set, intersections, null);
public LeastMedianOfSquaresEstimator(List<Line> setOfLines) {
this(setOfLines, null);
}
/**
@ -101,9 +95,8 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
}
};
intervals = new PriorityQueue<>(comparator);
intervals.add(new Interval(-100000, 100000));
intervals.add(new Interval(-10000, 10000));
heightsigmaMin = Double.MAX_VALUE;
List<Point> tmpIntersections = new ArrayList<>(intersections);
//(3.) Apply the following steps as long as the exists active intervals
boolean active = true;
@ -120,7 +113,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
} else {
//(c.) otherwise....
// get random intersections point...
Collections.shuffle(tmpIntersections);
Collection<Point> tmpIntersections = IntersectionComputer.getInstance().compute(setOfLines, interval.getLower(), interval.getUpper());
boolean found = false;
for (Point tmpIntersection : tmpIntersections) {
if (tmpIntersection.getX() > interval.getLower()
@ -154,7 +147,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
}
}
end = System.currentTimeMillis();
Logging.logInfo("Zeit: " + ((end - start) / 1000));
Logging.logInfo("=== E N D - L M S === " + ((end - start) / 1000));
return pepareResult();
}
@ -166,7 +159,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
* @return Anzahl der Schnittpunkte
*/
public int countInversions(Interval interval) {
return invCounter.run(set, interval);
return IntersectionComputer.getInstance().compute(setOfLines, interval.getLower(), interval.getUpper()).size();
}
@ -183,7 +176,8 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
//initialisiere die x-Queue mit den 2D Punkten und sortiere nach x-Lexikographischer Ordnung
List<Point> xQueue = new ArrayList<>();
for (Point point : intersections) {
Collection<Point> points = IntersectionComputer.getInstance().compute(setOfLines, interval.getLower(), interval.getUpper());
for (Point point : points) {
if (point.getX() >= interval.getLower() && point.getX() < interval.getUpper()) {
xQueue.add(point);
}
@ -271,7 +265,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
//y koordinaten der Schnittpunkte
List<Line> lines = new ArrayList<>();
for (Line p : set) {
for (Line p : setOfLines) {
lines.add(
new Line(pslab.getLower(), pslab.getUpper(), ((pslab.getLower() * p.getM()) + p.getB()),
((pslab.getUpper() * p.getM()) + p.getB())));
@ -333,7 +327,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
List<Double> ret = new ArrayList<>();
for (Line p : set) {
for (Line p : setOfLines) {
ret.add((p.getM() * u) + p.getB());
}
@ -354,7 +348,7 @@ public class LeastMedianOfSquaresEstimator implements Algorithm, Flow.Publisher<
//y Koordinaten für das kMinus brecalet
List<Double> intersections = new LinkedList<>();
for (Line line : set) {
for (Line line : setOfLines) {
intersections.add((px.getX() * line.getM()) + line.getB());
}
if (intersections.size() >= kMinusValue) {

View File

@ -2,20 +2,15 @@ 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.Presenter;
import de.wwwu.awolf.presenter.algorithms.Algorithm;
import de.wwwu.awolf.presenter.util.FastElementSelector;
import de.wwwu.awolf.presenter.util.IntersectionCounter;
import de.wwwu.awolf.presenter.util.Logging;
import de.wwwu.awolf.presenter.util.RandomSampler;
import de.wwwu.awolf.presenter.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.Flow;
@ -29,20 +24,19 @@ import java.util.concurrent.Flow;
public class RepeatedMedianEstimator implements Algorithm, Flow.Publisher<Data> {
private Presenter presenter;
private List<Line> set;
private Map<Line, Double> medianIntersections = new HashMap<>();
private Map<Line, ArrayList<Double>> intersectionAbscissas = new HashMap<>();
private List<Line> setOfLines;
private Interval interval;
private Interval original;
//in der Literatur als L_i, C_i, und R_i bekannt
private List<Double> countLeftSlab;
private List<Double> countCenterSlab;
private List<Double> countRightSlab;
private int countLeftSlab;
private int countCenterSlab;
private int countRightSlab;
//die Mengen L,C und R
private List<Line> linesInLeftSlab;
private List<Line> linesInCenterSlab;
private List<Line> linesInRightSlab;
//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;
@ -51,9 +45,6 @@ public class RepeatedMedianEstimator implements Algorithm, Flow.Publisher<Data>
private double kHigh;
private double beta;
private double thetaLow;
private double thetaHigh;
private double slope;
private double yInterception;
private Flow.Subscriber<? super AlgorithmData> subscriber;
@ -61,39 +52,41 @@ public class RepeatedMedianEstimator implements Algorithm, Flow.Publisher<Data>
/**
* Konstruktor
*
* @param set Liste der Geraden
* @param presenter Presenter (Beobachter)
* @param setOfLines Liste der Geraden
* @param presenter Presenter (Beobachter)
*/
public RepeatedMedianEstimator(List<Line> set, Presenter presenter) {
this.set = set;
public RepeatedMedianEstimator(List<Line> setOfLines, Presenter presenter) {
this.setOfLines = setOfLines;
this.presenter = presenter;
interval = new Interval(-10000, 10000);
n = set.size();
original = new Interval(-10000,10000);
n = setOfLines.size();
beta = 0.5;
countLeftSlab = new ArrayList<>();
countCenterSlab = new ArrayList<>();
countRightSlab = new ArrayList<>();
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.add(0d);
countRightSlab.add(0d);
countCenterSlab.add(n - 1.0);
intersectionAbscissas.put(set.get(i), new ArrayList<>());
countLeftSlab = 0;
countRightSlab = 0;
countCenterSlab = setOfLines.size();
}
linesInLeftSlab = new ArrayList<>();
linesInCenterSlab = new ArrayList<>(set);
linesInRightSlab = new ArrayList<>();
subscribe(presenter);
}
/**
* Konstruktor
*
* @param set Liste der Geraden
* @param setOfLines Liste der Geraden
*/
public RepeatedMedianEstimator(List<Line> set) {
this(set, null);
public RepeatedMedianEstimator(List<Line> setOfLines) {
this(setOfLines, null);
}
/**
@ -110,42 +103,46 @@ public class RepeatedMedianEstimator implements Algorithm, Flow.Publisher<Data>
long start;
long end;
start = System.currentTimeMillis();
double thetaLow = 0;
double thetaHigh = 0;
while (linesInCenterSlab.size() != 1) {
n = linesInCenterSlab.size();
while (countCenterSlab > 1) {
n = countCenterSlab;
r = Math.ceil(Math.pow(n, beta));
List<Line> lines = RandomSampler.run(linesInCenterSlab, r, linesInCenterSlab.size());
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<>();
for (Line l : lines) {
Double abscissa = estimateMedianIntersectionAbscissas(l);
medianIntersections.put(l, abscissa);
medianIntersectionAbscissas.add(abscissa);
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(set.size(), (Math.ceil(n * 0.5) - linesInLeftSlab.size())));
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();
countNumberOfIntersectionsAbscissas(thetaLow, thetaHigh);
//verkleinere das Intervall
contractIntervals();
contractIntervals(thetaLow, thetaHigh);
}
end = System.currentTimeMillis();
Logging.logInfo("Zeit: " + ((end - start) / 1000));
return pepareResult();
end = System.currentTimeMillis();
Logging.logInfo("=== E N D - R M === " + ((end - start) / 1000));
return pepareResult(thetaLow, thetaHigh);
}
@ -155,18 +152,20 @@ public class RepeatedMedianEstimator implements Algorithm, Flow.Publisher<Data>
* @param sampledLine Stichprobe von Geraden
* @return mediane x-Koordinate über den Schnittpunkten
*/
public Double estimateMedianIntersectionAbscissas(Line sampledLine) {
public Double estimateMedianIntersectionAbscissas(List<Line> lines, Line sampledLine) {
int index = Integer.parseInt(sampledLine.getId());
IntersectionCounter intersectionCounter = new IntersectionCounter();
List<Double> intersections = intersectionCounter.calculateIntersectionAbscissas(linesInCenterSlab, sampledLine);
List<Double> intersections = intersectionCounter.calculateIntersectionAbscissas(lines, sampledLine, original.getLower(), original.getUpper());
List<Double> left = intersectionCounter.calculateIntersectionAbscissas(lines, sampledLine, original.getLower(), interval.getLower());
List<Double> center = intersectionCounter.calculateIntersectionAbscissas(lines, sampledLine, interval.getLower(), interval.getUpper());
double ki = Math.ceil((n - 1) * 0.5) - FastElementSelector.randomizedSelect(countLeftSlab, index);
double i = (Math.ceil((Math.sqrt(n) * ki) / FastElementSelector.randomizedSelect(countCenterSlab, index)));
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())
else if (i >= intersections.size() && !intersections.isEmpty())
accessIndex = intersections.size() - 1;
else
accessIndex = (int) i;
@ -178,9 +177,9 @@ public class RepeatedMedianEstimator implements Algorithm, Flow.Publisher<Data>
* Berechnet die potenziell neuen Intervallgrenzen.
*/
public void computeSlabBorders() {
kLow = Math.max(1, Math.floor(((r * k) / (linesInCenterSlab.size()))
kLow = Math.max(1, Math.floor(((r * k) / (countCenterSlab))
- ((3 * Math.sqrt(r)) * (0.5))));
kHigh = Math.min(r, Math.floor(((r * k) / (linesInCenterSlab.size()))
kHigh = Math.min(r, Math.floor(((r * k) / (countCenterSlab))
+ ((3 * Math.sqrt(r)) * (0.5))));
}
@ -189,87 +188,56 @@ public class RepeatedMedianEstimator implements Algorithm, Flow.Publisher<Data>
* 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) {
List<Double> intersections = intersectionAbscissas.get(line);
int index = Integer.parseInt(line.getId());
int left = 0;
int center = 0;
int right = 0;
public void countNumberOfIntersectionsAbscissas(final double lower, final double upper) {
IntersectionComputer instance = IntersectionComputer.getInstance();
for (Double intersection : intersections) {
if (intersection <= thetaLow) {
left++;
} else if (intersection > thetaLow && intersection <= thetaHigh) {
center++;
} else if (intersection > thetaHigh) {
right++;
}
}
countLeftSlab.set(index, (double) left);
countCenterSlab.set(index, (double) center);
countRightSlab.set(index, (double) right);
}
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();
}
/**
* TODO bad idea!!!
* 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++) {
public void contractIntervals(final double lower, final double upper) {
double max = Math.max(countLeftSlab, Math.max(countCenterSlab, countRightSlab));
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);
}
}
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 (linesInLeftSlab.size() < Math.ceil(n * 0.5) && Math.ceil(n * 0.5) <= linesInLeftSlab.size() + linesInCenterSlab.size()) {
interval.setLower(thetaLow + 0.1);
interval.setUpper(thetaHigh);
}
// wähle L als C
else if (Math.ceil(n * 0.5) <= linesInLeftSlab.size()) {
interval.setUpper(thetaLow);
}
//wähle R als C
else if (linesInLeftSlab.size() + linesInCenterSlab.size() < Math.ceil(n * 0.5) && Math.ceil(n * 0.5) <= (linesInLeftSlab.size() + linesInCenterSlab.size() + linesInRightSlab.size())) {
interval.setLower(thetaHigh - 0.1);
if (newIntervalIsC) {
interval.setLower(lower);
interval.setUpper(upper);
} else if (newIntervalIsL) {
interval.setUpper(lower);
} else if (newIntervalIsR) {
interval.setLower(upper);
}
}
private Line pepareResult() {
if (this.subscriber != null) {
double m = thetaLow;
double b = (-1) * (
(linesInCenterSlab.get(0).getM() * (thetaLow)) + linesInCenterSlab.get(0)
.getB());
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()));
});
slope = m;
yInterception = b;
yInterception = FastElementSelector.randomizedSelect(potentialYInterceptions, Math.floor(potentialYInterceptions.size() * 0.5 ));
if (this.subscriber != null) {
AlgorithmData data = new AlgorithmData();
data.setType(SubscriberType.RM);
data.setLineData(new Line(m, b));
data.setLineData(new Line(getSlope(), getyInterception()));
this.subscriber.onNext(data);
} else {
double m = thetaLow;
double b = (-1) * ((linesInCenterSlab.get(0).getM() * (thetaLow)) + linesInCenterSlab.get(0).getB());
slope = m;
yInterception = b;
}
return new Line(getSlope(), getyInterception());
@ -341,21 +309,21 @@ public class RepeatedMedianEstimator implements Algorithm, Flow.Publisher<Data>
/**
* @return verteilung der Punkte
*/
public List<Double> getCountLeftSlab() {
public int getCountLeftSlab() {
return countLeftSlab;
}
/**
* @return verteilung der Punkte
*/
public List<Double> getCountCenterSlab() {
public int getCountCenterSlab() {
return countCenterSlab;
}
/**
* @return verteilung der Punkte
*/
public List<Double> getCountRightSlab() {
public int getCountRightSlab() {
return countRightSlab;
}

View File

@ -8,15 +8,9 @@ import de.wwwu.awolf.model.communication.Data;
import de.wwwu.awolf.model.communication.SubscriberType;
import de.wwwu.awolf.presenter.Presenter;
import de.wwwu.awolf.presenter.algorithms.Algorithm;
import de.wwwu.awolf.presenter.util.BinomialCoeffizient;
import de.wwwu.awolf.presenter.util.FastElementSelector;
import de.wwwu.awolf.presenter.util.IntersectionCounter;
import de.wwwu.awolf.presenter.util.RandomSampler;
import de.wwwu.awolf.presenter.util.*;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.concurrent.Flow;
/**
@ -32,12 +26,8 @@ public class TheilSenEstimator implements Algorithm, Flow.Publisher<Data> {
private final double NEGATIV_INF = -99999.0;
private final double EPSILON = 0.00001;
private List<Line> setOfLines;
private List<Point> setOfIntersections;
private List<Point> intervalIntersections;
private List<Double> sampledIntersections;
//wird benötigt um den y Achsenabschnitt zu Berechnen
private List<Double> yCoordinates;
private List<Double> xCoordinates;
private List<Point> sampledIntersections;
//Hilfsvariablen (siehe original Paper)
private double j;
private int jA;
@ -53,24 +43,21 @@ public class TheilSenEstimator implements Algorithm, Flow.Publisher<Data> {
private double slope;
private double yInterception;
private Flow.Subscriber<? super AlgorithmData> subscriber;
private Collection<Point> setOfIntersections;
/**
* Konstruktor
*
* @param setOfLines Liste der Geraden
* @param setOfIntersections Liste der Schnittpunkte
* @param presenter Presenter (Beobachter)
*/
public TheilSenEstimator(List<Line> setOfLines, List<Point> setOfIntersections, Presenter presenter) {
public TheilSenEstimator(List<Line> setOfLines, Presenter presenter) {
this.setOfLines = new ArrayList<>(setOfLines);
this.setOfIntersections = new ArrayList<>(setOfIntersections);
this.intervalIntersections = new ArrayList<>(setOfIntersections);
this.setOfIntersections = new HashSet<>();
this.n = setOfLines.size();
this.sampledIntersections = new ArrayList<>();
this.yCoordinates = new ArrayList<>();
this.xCoordinates = new ArrayList<>();
this.N = BinomialCoeffizient.run(n, 2);
//this.k = Integer.valueOf((int) (N * 0.5)) - 1;
this.k = (int) (N / 2);
@ -83,10 +70,9 @@ public class TheilSenEstimator implements Algorithm, Flow.Publisher<Data> {
* Konstruktor
*
* @param setOfLines Liste der Geraden
* @param setOfIntersections Liste der Schnittpunkte
*/
public TheilSenEstimator(List<Line> setOfLines, List<Point> setOfIntersections) {
this(setOfLines, setOfIntersections, null);
public TheilSenEstimator(List<Line> setOfLines) {
this(setOfLines, null);
}
/**
@ -105,7 +91,7 @@ public class TheilSenEstimator implements Algorithm, Flow.Publisher<Data> {
break;
} else {
//Anzahl der Schnittpunkte im Intervall [-Inf, a)
int numberOfIntersections = getOpenIntervalSize(NEGATIV_INF, interval.getLower(), setOfIntersections);
int numberOfIntersections = getOpenIntervalSize(NEGATIV_INF, interval.getLower());
//Randomized Interpolating Search
j = (r / N) * (double) (k - numberOfIntersections);
@ -119,20 +105,27 @@ public class TheilSenEstimator implements Algorithm, Flow.Publisher<Data> {
do {
//zufällige Stichprobe
sampledIntersections = RandomSampler.run(intervalIntersections, r);
aVariant = FastElementSelector.randomizedSelect(sampledIntersections, jA);
bVariant = FastElementSelector.randomizedSelect(sampledIntersections, jB);
aVariant = FastElementSelector.randomizedSelect(getIntersectionAbscissas(sampledIntersections), jA);
bVariant = FastElementSelector.randomizedSelect(getIntersectionAbscissas(sampledIntersections), jB);
} while (!checkCondition());
interval.setLower(aVariant);
interval.setUpper(bVariant);
intervalIntersections = getOpenIntervalElements(interval.getLower(), interval.getUpper());
N = getOpenIntervalSize(interval.getLower(), interval.getUpper(), intervalIntersections);
N = getOpenIntervalSize(interval.getLower(), interval.getUpper());
}
}
return pepareResult();
}
private List<Double> getIntersectionAbscissas(List<Point> interections) {
List<Double> abscissas = new ArrayList<>();
interections.forEach(e -> abscissas.add(e.getX()));
return abscissas;
}
/**
* Diese Funktion überprüft ob die Bedingung für das Interval erfüllt ist. Dabei muss der k-te
@ -183,15 +176,10 @@ public class TheilSenEstimator implements Algorithm, Flow.Publisher<Data> {
* @param b obere Grenze des Intrvals
* @return Anzahl der Schnittpunkte im Interval (a,b)
*/
public int getOpenIntervalSize(double a, double b, List<Point> set) {
int counter = 0;
for (int i = 0; i < set.size(); i++) {
Point x = set.get(i);
if (x.getX() > a && x.getX() < b) {
counter++;
}
}
return counter;
public int getOpenIntervalSize(double a, double b) {
Collection<Point> intersections = IntersectionComputer.getInstance().compute(setOfLines, a, b);
setOfIntersections.addAll(intersections);
return intersections.size();
}
/**
@ -227,17 +215,19 @@ public class TheilSenEstimator implements Algorithm, Flow.Publisher<Data> {
resultAbscissas.add(p.getX());
}
List<Double> yCoords = new ArrayList<>();
for (Point p : setOfIntersections) {
yCoordinates.add(p.getY());
yCoords.add(p.getY());
}
double pseudoIndex = getOpenIntervalSize(NEGATIV_INF, interval.getLower(), setOfIntersections) * 1.0;
double pseudoIndex = getOpenIntervalSize(NEGATIV_INF, interval.getLower()) * 1.0;
m = FastElementSelector.randomizedSelect(resultAbscissas, k - pseudoIndex);
Set<Double> unique = new LinkedHashSet<>(yCoordinates);
yCoordinates.clear();
yCoordinates.addAll(unique);
b = FastElementSelector.randomizedSelect(yCoordinates, yCoordinates.size() * 0.5) * -1;
Set<Double> unique = new LinkedHashSet<>(yCoords);
yCoords.clear();
yCoords.addAll(unique);
b = FastElementSelector.randomizedSelect(yCoords, yCoords.size() * 0.5) * -1;
slope = m;
yInterception = b;

View File

@ -16,13 +16,12 @@ import java.util.Map;
*/
public class DatasetGenerator {
private static SecureRandom random;
/**
* Konstruktor
*/
private DatasetGenerator() {
random = new SecureRandom();
}
@ -34,6 +33,7 @@ public class DatasetGenerator {
* @return Liste des Geraden
*/
public static List<Line> generateDataLines(List<Line> lines, int n) {
double m = 5d;
double b = 0d;
@ -42,6 +42,7 @@ public class DatasetGenerator {
//speichere die Koordinaten in einer HashMap, damit keine Punkte
//entstehen deren x-Koordinate zu sehr beieinander liegt.
SecureRandom random = new SecureRandom();
while (size < n) {
double y = random.nextGaussian();
double signal = m * y + b;
@ -54,8 +55,8 @@ public class DatasetGenerator {
}
int idx = lines.size();
for (Double d : points.keySet()) {
Line line = new Line(d, points.get(d));
for (Map.Entry<Double, Double> d : points.entrySet()) {
Line line = new Line(d.getKey(), d.getValue());
line.setId(idx + "");
lines.add(line);
idx++;

View File

@ -2,7 +2,6 @@ package de.wwwu.awolf.presenter.data.io;
import com.opencsv.CSVWriter;
import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.model.communication.Data;
import de.wwwu.awolf.presenter.util.Logging;
import java.io.File;
@ -43,7 +42,7 @@ public class DataExporter implements Runnable {
CSVWriter writer = null;
try {
writer = new CSVWriter(new FileWriter(file), ',');
writer = new CSVWriter(new FileWriter(file));
String[] entries = new String[3];
for (Line line : lines) {
entries[0] = line.getId();

View File

@ -24,15 +24,15 @@ public class AlgorithmComparison {
private final Map<Algorithm.Type, Algorithm> algorithmMap;
private final CompletionService<Line> completionService;
public AlgorithmComparison(List<Algorithm.Type> types, List<Line> lines, List<Point> nodes) {
public AlgorithmComparison(List<Algorithm.Type> types, List<Line> lines) {
this.types = types;
this.executorService = Executors.newFixedThreadPool(3);
completionService = new ExecutorCompletionService<>(this.executorService);
algorithmMap = new EnumMap<>(Algorithm.Type.class);
algorithmMap.put(Algorithm.Type.LMS, new LeastMedianOfSquaresEstimator(lines, nodes));
algorithmMap.put(Algorithm.Type.LMS, new LeastMedianOfSquaresEstimator(lines));
algorithmMap.put(Algorithm.Type.RM, new RepeatedMedianEstimator(lines));
algorithmMap.put(Algorithm.Type.TS, new TheilSenEstimator(lines, nodes));
algorithmMap.put(Algorithm.Type.TS, new TheilSenEstimator(lines));
algorithmMap.put(Algorithm.Type.NAIV_LMS, new NaivLeastMedianOfSquaresEstimator(lines));
algorithmMap.put(Algorithm.Type.NAIV_RM, new NaivRepeatedMedianEstimator(lines));
algorithmMap.put(Algorithm.Type.NAIV_TS, new NaivTheilSenEstimator(lines));

View File

@ -67,9 +67,6 @@ public class EvaluateAlgorithms implements Runnable, Flow.Publisher<Data> {
this.type = type;
this.iterations = n;
this.alg = alg;
IntersectionComputer computer = new IntersectionComputer(arrangement.getLines());
arrangement.setNodes(computer.compute());
}
/**
@ -93,14 +90,11 @@ public class EvaluateAlgorithms implements Runnable, Flow.Publisher<Data> {
this.type = type;
this.alg = alg;
IntersectionComputer computer = new IntersectionComputer(arrangement.getLines());
arrangement.setNodes(computer.compute());
}
private Map<Algorithm.Type, Map<String, String>> benchmarkSameEstimator(final Algorithm.Type advanced, final Algorithm.Type naiv) {
Logging.logInfo("AlgorithmComparison with Types: " + advanced.name() + ", " + naiv.name());
AlgorithmComparison comparison = new AlgorithmComparison(Arrays.asList(naiv, advanced), Collections.unmodifiableList(arrangement.getLines()), Collections.unmodifiableList(arrangement.getNodes()));
AlgorithmComparison comparison = new AlgorithmComparison(Arrays.asList(naiv, advanced), Collections.unmodifiableList(arrangement.getLines()));
ComparisonResult comparisonResult = comparison.compare();
@ -115,11 +109,10 @@ public class EvaluateAlgorithms implements Runnable, Flow.Publisher<Data> {
private Map<Algorithm.Type, Map<String, String>> benchmarkDifferentEstimators(List<Algorithm.Type> types) {
Logging.logInfo("AlgorithmComparison with Types: " + types);
AlgorithmComparison comparison = new AlgorithmComparison(types, Collections.unmodifiableList(arrangement.getLines()), Collections.unmodifiableList(arrangement.getNodes()));
AlgorithmComparison comparison = new AlgorithmComparison(types, Collections.unmodifiableList(arrangement.getLines()));
ComparisonResult comparisonResult = comparison.compare();
Map<String, String> multipleResults = new HashMap<>();
types.forEach(type -> this.resultMapping.put(type, getPercentigeErrorBasedMeasure(arrangement.getLines(), comparisonResult, type)));
types.forEach(typeEntry -> this.resultMapping.put(typeEntry, getPercentigeErrorBasedMeasure(arrangement.getLines(), comparisonResult, typeEntry)));
Logging.logInfo("finished with execution of the algorithms.");
return this.resultMapping;
}

View File

@ -1,159 +0,0 @@
package de.wwwu.awolf.presenter.evaluation.measures;
import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.model.communication.Data;
import de.wwwu.awolf.model.communication.SubscriberType;
import de.wwwu.awolf.model.communication.TypeData;
import de.wwwu.awolf.presenter.Presenter;
import de.wwwu.awolf.presenter.util.Logging;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.Flow;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
*
* @Author: Armin Wolf
* @Email: a_wolf28@uni-muenster.de
* @Date: 17.09.2017.
*/
public class PictureProcessor implements Flow.Publisher<Data> {
private Mat image;
private Mat contour;
private Presenter presenter;
private File file;
private ArrayList<MatOfPoint> contours;
private double contourLength;
private Flow.Subscriber<? super Data> subscriber;
/**
* Konstruktor
*
* @param presenter Presenter
* @param file Bilddatei
*/
public PictureProcessor(Presenter presenter, File file) {
this.file = file;
this.presenter = presenter;
subscribe(presenter);
}
/**
* startet den Import des Bild und die Vorverarbeitung
*/
public void run() {
image = Imgcodecs.imread(file.getAbsolutePath());
contour = process(image);
contourLength = image.width() * 0.3;
createInputData();
}
/**
* Vorverarbeitung des Eingabebilds. Dabei wird auf verschiedene OpenCV Methoden zurückgegriffen.
*
* @param image Eingabebild
* @return Matrix representation des Bilds
*/
private Mat process(Mat image) {
Mat threshold = new Mat(image.width(), image.height(), CvType.CV_8UC1);
Mat source = new Mat(image.width(), image.height(), CvType.CV_8UC1);
Imgcodecs.imwrite(file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")) + "-orig.png", image);
Imgproc.cvtColor(image, source, Imgproc.COLOR_BGR2GRAY);
Imgcodecs.imwrite(file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")) + "-Greyscale.png", source);
Imgproc.GaussianBlur(source, threshold, new Size(3, 3), 0, 0);
Imgproc.Canny(threshold, source, 300, 600, 5, true);
Imgcodecs.imwrite(file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")) + "-Canny.png", source);
//Konturen berechnen und filtern
contours = new ArrayList<>();
Imgproc.findContours(source, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
Mat viscont = new Mat(source.size(), source.type());
double minArea = 50;
double maxArea = 0.2 * image.cols() * image.rows();
for (int i = 0; i < contours.size(); i++) {
double acutualArea = Imgproc.contourArea(contours.get(i));
if (minArea < acutualArea && maxArea > acutualArea) {
Imgproc.drawContours(viscont, contours, i, new Scalar(255, 0, 0), 1);
}
}
Imgcodecs.imwrite(file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")) + "-Contour.png", viscont);
Mat resized = new Mat();
Imgproc.resize(viscont, resized, new Size(560, 560));
SwingUtilities.invokeLater(() -> {
JDialog dialog = new JDialog();
dialog.setSize(560, 560);
JLabel label = new JLabel();
label.setSize(560, 560);
label.setIcon(new ImageIcon(toBufferedImage(resized)));
dialog.add(label);
dialog.setVisible(true);
});
return viscont;
}
/**
* Das Bild wird passend umgewandelt, um im nächsten Schritt visualisiert werden zu können.
*
* @param m Matrix representation des Bilds
* @return visualisierbares Bild
*/
private BufferedImage toBufferedImage(Mat m) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (m.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
int bufferSize = m.channels() * m.cols() * m.rows();
byte[] b = new byte[bufferSize];
m.get(0, 0, b); // get all the pixels
BufferedImage image = new BufferedImage(m.cols(), m.rows(), type);
final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
return image;
}
/**
* Das gefilerte Bild ist bereit ins Modell aufgenommen zu werden um darauf dann die Algorithmen laufen zu lassen.
*/
private void createInputData() {
Thread t = new Thread(() -> {
double minArea = 50;
double maxArea = 0.2 * image.cols() * image.rows();
int id = 0;
for (int j = 0; j < contours.size(); j++) {
Point[] p = contours.get(j).toArray();
double acutualArea = Imgproc.contourArea(contours.get(j));
if (minArea < acutualArea && maxArea > acutualArea) {
for (int i = 0; i < p.length; i++) {
Line line = new Line(-1 * (500 - p[i].x), p[i].y);
line.setId("" + id++);
presenter.getModel().getLines().add(line);
}
}
}
TypeData data = new TypeData();
data.setType(SubscriberType.PICTURE);
this.subscriber.onNext(data);
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
Logging.logError(e.getMessage(), e);
Thread.currentThread().interrupt();
}
}
@Override
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
this.subscriber = subscriber;
}
}

View File

@ -21,6 +21,7 @@ public class FastElementSelector {
* @return das Element
*/
public static Double randomizedSelect(List<Double> a, double i) {
int start = 0;
int end = a.size() - 1;

View File

@ -1,13 +1,16 @@
package de.wwwu.awolf.presenter.util;
import de.wwwu.awolf.model.Interval;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.model.Point;
import org.jfree.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
@ -18,32 +21,68 @@ import java.util.TreeSet;
*/
public class IntersectionComputer {
private List<Line> lines;
private Set<Point> intersections;
private Double xMinimum;
private Double xMaximum;
private Double yMinimum;
private Double yMaximum;
private Thread[] worker;
private static IntersectionComputer instance;
/**
* Konstruktor
*
* @param lines Liste der Geraden
*/
public IntersectionComputer(List<Line> lines) {
this.lines = lines;
this.worker = new Thread[4];
this.intersections = new TreeSet<>();
xMinimum = Double.MAX_VALUE;
xMaximum = Double.MIN_VALUE;
yMinimum = Double.MAX_VALUE;
yMaximum = Double.MIN_VALUE;
private IntersectionComputer() {
}
private class RecursiveComputationTask extends RecursiveTask<Collection<Point>> {
private static final int THRESHOLD = 20;
private final List<Line> lines;
private final List<Line> fullList;
private final double lower;
private final double upper;
public RecursiveComputationTask(final List<Line> fullList, final List<Line> lines, final double lower, final double upper) {
this.lines = lines;
this.fullList = fullList;
this.lower = lower;
this.upper = upper;
}
@Override
protected Collection<Point> compute() {
if (this.lines.isEmpty()){
return Collections.emptyList();
} else if (this.lines.size() > THRESHOLD) {
Logging.logInfo("Bigger than threshold, split into subtask.");
return ForkJoinTask.invokeAll(createSubTask()).stream().map(ForkJoinTask::join).flatMap(Collection::stream).collect(Collectors.toList());
} else {
return work(this.lines, this.lines, this.lower, this.upper);
}
}
private Collection<RecursiveComputationTask> createSubTask() {
List<RecursiveComputationTask> dividedTasks = new ArrayList<>();
dividedTasks.add(new RecursiveComputationTask(this.fullList, this.lines.subList(0, this.lines.size() / 2), this.lower, this.upper));
dividedTasks.add(new RecursiveComputationTask(this.fullList, this.lines.subList(this.lines.size() / 2, this.lines.size()), this.lower, this.upper));
return dividedTasks;
}
private Collection<Point> work(List<Line> fullList, List<Line> lines, double lower, double higher) {
Set<Point> points = new HashSet<>();
List<List<Line>> lists = Lists.cartesianProduct(new ArrayList<>(fullList), new ArrayList<>(lines));
lists.forEach(entry -> {
if (entry.get(0).doIntersect(entry.get(1), lower, upper)) {
Point intersect = entry.get(0).intersect(entry.get(1));
if (intersect.getX() > lower && intersect.getX() <= higher) {
points.add(intersect);
}
}
});
return new HashSet<>(points);
}
}
/**
* Berechnet zu einer gegebenen Menge von dualen Geraden die Schnittpunkte. Dafür wird ein modifizierter Merge-Sort
* Algorithmus verwendett. Um die Performance zu steigern wird die Berechnung ab einer passenden Größe auf vier
@ -53,141 +92,21 @@ public class IntersectionComputer {
* @param higher obere Schranke
* @return Liste der Schnittpunkte
*/
public ArrayList<Point> compute(final double lower, final double higher) {
public Collection<Point> compute(final List<Line> lines, final double lower, final double higher) {
Logging.logInfo("Open ForkJoinPool");
ForkJoinPool pool = ForkJoinPool.commonPool();
RecursiveComputationTask recursiveComputationTask = new RecursiveComputationTask(lines, lines, lower, higher);
pool.execute(recursiveComputationTask);
return recursiveComputationTask.join();
}
if (lines.size() > 16) {
worker[0] = new Thread(() -> {
work(lines.subList(0, (lines.size() / 4)), lower, higher);
});
worker[0].start();
worker[1] = new Thread(() -> {
work(lines.subList((lines.size() / 4) + 1, (lines.size() / 2)), lower, higher);
});
worker[1].start();
worker[2] = new Thread(() -> {
work(lines.subList((lines.size() / 2) + 1, 3 * (lines.size() / 4)), lower, higher);
});
worker[2].start();
worker[3] = new Thread(() -> {
work(lines.subList(3 * (lines.size() / 4) + 1, (lines.size())), lower, higher);
});
worker[3].start();
for (Thread t : worker) {
try {
t.join();
} catch (InterruptedException e) {
Logging.logError(e.getMessage(), e);
Thread.currentThread().interrupt();
}
}
} else {
work(lines, lower, higher);
public static IntersectionComputer getInstance() {
if (instance == null) {
instance = new IntersectionComputer();
Logging.logInfo("Created instance of IntersectionComputer");
}
return new ArrayList<>(intersections);
return instance;
}
/**
* Berechnet zu einer gegebenen Menge von dualen Geraden die Schnittpunkte. Dafür wird ein modifizierter Merge-Sort
* Algorithmus verwendett. Um die Performance zu steigern wird die Berechnung ab einer passenden Größe auf vier
* Threads ausgelagert.
*
* @return Liste der Schnittpunkte
*/
public ArrayList<Point> compute() {
return compute(-99999, 99999);
}
private void work(List<Line> lines, double lower, double higher) {
IntersectionCounter counter = new IntersectionCounter();
int count = counter.run(lines, new Interval(lower, higher));
ArrayList<Point> points = counter.calculateIntersectionAbscissas();
for (Point p : points) {
if (!isFound(p)) {
addIntersection(p);
setRanges(p);
}
}
}
/**
* Synchronisierter Zugriff auf die Liste der Geraden
*
* @return Liste der Geraden
*/
public synchronized List<Line> getLines() {
return lines;
}
/**
* Synchronisierter hinzufügen eines Schnittpunkts
*
* @param p Schnittpunkt
*/
public synchronized void addIntersection(Point p) {
this.intersections.add(p);
}
/**
* Synchronisiertes abfragen ob ein Schnittpunkt bereits gefunden wurde.
*
* @param p Schnittpunkt
* @return <code>true</code>, falls der Schnittpunkt p bereits gefunden wurde
*/
public synchronized boolean isFound(Point p) {
return intersections.contains(p);
}
/**
* Zu einem Punkt werden die minimalen, maximalen x- und y-Koordinaten überprüft und ggf.
* neu gesetzt
*
* @param point Schnittpunkt
*/
public void setRanges(Point point) {
xMaximum = (point.getX() > xMaximum) ? point.getX() : xMaximum;
xMinimum = (point.getX() < xMinimum) ? point.getX() : xMinimum;
yMaximum = (point.getY() > yMaximum) ? point.getY() : yMaximum;
yMinimum = (point.getY() < yMinimum) ? point.getY() : yMinimum;
}
/**
* Synchronisierter Zugriff auf die minimale x-Koordiante
*
* @return minimale x-Koordiante
*/
public synchronized Double getxMinimum() {
return xMinimum;
}
/**
* Synchronisierter Zugriff auf die maximale x-Koordinate
*
* @return maximale x-Koordinate
*/
public synchronized Double getxMaximum() {
return xMaximum;
}
/**
* Synchronisierter Zugriff auf die minimale y-Koordinate
*
* @return minimale y-Koordinate
*/
public synchronized Double getyMinimum() {
return yMinimum;
}
/**
* Synchronisierter Zugriff auf die maximale y-Koordinate
*
* @return maximale y-Koordinate
*/
public synchronized Double getyMaximum() {
return yMaximum;
}
}

View File

@ -210,20 +210,43 @@ public class IntersectionCounter {
* @param sampledLine eine spezielle Gerade
* @return Liste mit x Koordinaten der Schnittpunkte
*/
public List<Double> calculateIntersectionAbscissas(List<Line> set, Line sampledLine) {
public List<Double> calculateIntersectionAbscissas(List<Line> set, Line sampledLine, double lower, double upper) {
List<Line> lines = new LinkedList<>(set);
List<Double> intersections = new ArrayList<>();
double intersection;
Set<Double> intersections = new HashSet<>();
for (Line line : lines) {
if (line != sampledLine) {
intersection = (line.getB() - sampledLine.getB()) / (sampledLine.getM() - line.getM());
intersections.add(intersection);
if (sampledLine.doIntersect(line, lower, upper)){
intersections.add(sampledLine.intersect(line).getX());
}
}
}
return intersections;
return new ArrayList<>(intersections);
}
/**
* Berechnet die Schnittpunkte zwischen einer gegebenen Gerade und einer Menge an Geraden.
*
* @param set Menge an Geraden
* @param sampledLine eine spezielle Gerade
* @return Liste mit x Koordinaten der Schnittpunkte
*/
public List<Double> calculateIntersectionYInterception(List<Line> set, Line sampledLine, double lower, double upper) {
List<Line> lines = new LinkedList<>(set);
Set<Double> intersections = new HashSet<>();
for (Line line : lines) {
if (line != sampledLine) {
if (sampledLine.doIntersect(line, lower, upper)){
intersections.add(sampledLine.intersect(line).getY());
}
}
}
return new ArrayList<>(intersections);
}
}

View File

@ -6,6 +6,9 @@ import org.apache.log4j.Logger;
public class Logging {
private static Logger logger = Logger.getRootLogger();
private Logging() {
}
public static void logInfo(final String message, Throwable throwable) {
logger.info(message, throwable);
}

View File

@ -3,6 +3,7 @@ package de.wwwu.awolf.presenter.util;
import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.model.Point;
import java.io.Serializable;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
@ -29,38 +30,14 @@ public class RandomSampler {
* @param r Anzahl der zu wählenden Geraden
* @return <code>r</code> Elementige zufällige Stichprobe an Geraden
*/
public static List<Line> run(List<Line> set, Double r, Integer indexOfEnd) {
List<Line> sampledLines = new ArrayList<>();
for (int i = 0; i < r; i++) {
sampledLines.add(set.get(random.nextInt(indexOfEnd)));
public static <T extends Object> List<T> run(List<T> set, Double r) {
int index = 0;
List<T> sampled = new ArrayList<>();
for (int i=0; i<r; i++) {
index = random.nextInt(set.size());
sampled.add(set.get(index));
}
return sampledLines;
return sampled;
}
/**
* Diese Methode liefert eine <code>r</code> Elementige zufällige Stichprobe van Schnittpunkten.
*
* @param set Die gesammtmenge der Geraden aus denen gewählt werden soll
* @param r Anzahl der zu wählenden Geraden
* @return <code>r</code> Elementige zufällige Stichprobe an Schnittpunkten
*/
public static List<Double> run(List<Point> set, Double r) {
List<Double> sampledLines = new ArrayList<>();
for (Point p : set) {
sampledLines.add(p.getX());
}
int inputSize = sampledLines.size();
for (int i = 0; i < r; i++) {
int indexToSwap = i + random.nextInt(inputSize - i);
Double temp = sampledLines.get(i);
sampledLines.set(i, sampledLines.get(indexToSwap));
sampledLines.set(indexToSwap, temp);
}
return new ArrayList<>(sampledLines.subList(0, r.intValue()));
}
}

View File

@ -20,8 +20,6 @@ import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -91,36 +89,6 @@ public class MainFrame extends JFrame {
* visualisierungs methoden
******************************************************************************************************************/
/**
* Erzeugt den Dialog für die duale Darstellung
*/
public void createDualityDialog() {
arrangement = new DualityPanel();
arrangementDialog = new JDialog();
arrangementDialog.setTitle("Dualraum - Dialog");
arrangementDialog.setMinimumSize(new Dimension(1024, 768));
arrangementDialog.setPreferredSize(new Dimension(800, 800));
arrangementDialog.setLocationRelativeTo(this);
arrangementDialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
arrangementButton.addActionListener(new DualityVisualizerListener((Presenter) getPresenter()));
arrangement.clear();
arrangement.setPrameters(getPresenter().getModel().getLines(),
getPresenter().getModel().getNodes(),
getPresenter().getModel().getxMinimum(),
getPresenter().getModel().getxMaximum(),
getPresenter().getModel().getyMinimum(),
getPresenter().getModel().getyMaximum());
arrangement.createArrangement();
SwingUtilities.invokeLater(() -> {
arrangementDialog.add(arrangement);
arrangementDialog.setLocationRelativeTo(this);
arrangementDialog.revalidate();
arrangementDialog.repaint();
arrangementDialog.setVisible(true);
});
}
/**
* Visualisiert das Ergebnis des LMS-Schätzers
*
@ -427,12 +395,11 @@ public class MainFrame extends JFrame {
menu.addActionListeners();
//action listener für diese Klasse
arrangementButton.addActionListener(new DualityVisualizerListener((Presenter) getPresenter()));
lmsPanel.getStartButton().addActionListener(new StartAlgorithmListener(((Presenter) getPresenter()), lmsPanel));
rmPanel.getStartButton().addActionListener(new StartAlgorithmListener(((Presenter) getPresenter()), rmPanel));
tsPanel.getStartButton().addActionListener(new StartAlgorithmListener(((Presenter) getPresenter()), tsPanel));
importButton.addActionListener(new ImportDataListener((Presenter) this.getPresenter(), this));
exportButton.addActionListener(new ExportDataListener((Presenter) this.getPresenter(), this));
importButton.addActionListener(new ImportDataListener((Presenter) this.getPresenter()));
exportButton.addActionListener(new ExportDataListener((Presenter) this.getPresenter()));
generateButton.addActionListener(new GenerateDataListener((Presenter) this.getPresenter()));
}

View File

@ -75,11 +75,13 @@ public class MenuBar {
this.exitItem.addActionListener(e -> {
System.exit(0);
});
this.evaluateItem.addActionListener(e -> {
view.showEvauluationDialog();
});
this.importItem.addActionListener(new ImportDataListener((Presenter) view.getPresenter(), view));
this.exportItem.addActionListener(new ExportDataListener((Presenter) view.getPresenter(), view));
this.importItem.addActionListener(new ImportDataListener((Presenter) view.getPresenter()));
this.exportItem.addActionListener(new ExportDataListener((Presenter) view.getPresenter()));
this.generateItem.addActionListener(new GenerateDataListener((Presenter) view.getPresenter()));
this.aboutItem.addActionListener(e -> {
SwingUtilities.invokeLater(() -> {

View File

@ -1,35 +0,0 @@
package de.wwwu.awolf.view.listener;
import de.wwwu.awolf.presenter.Presenter;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
*
* @Author: Armin Wolf
* @Email: a_wolf28@uni-muenster.de
* @Date: 10.09.2017.
*/
public class DualityVisualizerListener implements ActionListener {
private Presenter presenter;
/**
* Konstruktor
*
* @param presenter Presenter
*/
public DualityVisualizerListener(Presenter presenter) {
this.presenter = presenter;
}
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(() -> {
presenter.visualizeDualLines();
});
}
}

View File

@ -1,6 +1,7 @@
package de.wwwu.awolf.view.listener;
import de.wwwu.awolf.presenter.Presenter;
import de.wwwu.awolf.presenter.util.Logging;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
@ -20,36 +21,32 @@ import java.io.File;
public class ExportDataListener implements ActionListener {
private Presenter presenter;
private Container component;
/**
* Konstruktor
*
* @param presenter Presenter
* @param component visuelle Elternkomponente
*/
public ExportDataListener(Presenter presenter, Container component) {
public ExportDataListener(Presenter presenter) {
this.presenter = presenter;
this.component = component;
}
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(() -> {
File file = null;
JFileChooser chooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
JFileChooser chooser = new JFileChooser();
chooser.setPreferredSize(new Dimension(800, 700));
chooser.setFileFilter(new FileNameExtensionFilter("Comma-Separated Value, (*.csv)", "csv", "text"));
chooser.setMultiSelectionEnabled(false);
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
if (chooser.showSaveDialog(component) == JFileChooser.APPROVE_OPTION) {
//Logging.logInfo ("Datei "+chooser.getSelectedFile()+ " ausgewählt.");
if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
Logging.logInfo ("Datei "+chooser.getSelectedFile()+ " ausgewählt.");
file = chooser.getSelectedFile();
String filename = file.getAbsolutePath().contains(".csv") ? file.getAbsolutePath() : file.getAbsolutePath().concat(".csv");
File withExtension = new File(filename);
final File input = withExtension;
final File input = new File(filename);
Thread t = new Thread(() -> presenter.startExport(input));
t.start();
}

View File

@ -2,6 +2,7 @@ package de.wwwu.awolf.view.listener;
import de.wwwu.awolf.presenter.Presenter;
import de.wwwu.awolf.presenter.data.DataProvider;
import de.wwwu.awolf.presenter.util.Logging;
import javax.swing.*;
import java.awt.*;
@ -36,6 +37,7 @@ public class GenerateDataListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(() -> {
Logging.logInfo("Thread: " + Thread.currentThread().getName());
if (dialog == null || !dialog.isVisible()) {
dialog = new JDialog();
dialog.setTitle("generiere Datensatz");

View File

@ -1,6 +1,7 @@
package de.wwwu.awolf.view.listener;
import de.wwwu.awolf.presenter.Presenter;
import de.wwwu.awolf.presenter.util.Logging;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
@ -20,32 +21,29 @@ import java.io.File;
public class ImportDataListener implements ActionListener {
private Presenter presenter;
private Container component;
/**
* Konstruktor
*
* @param presenter Presenter
* @param component visuelle Elternkomponente
*/
public ImportDataListener(Presenter presenter, Container component) {
public ImportDataListener(Presenter presenter) {
this.presenter = presenter;
this.component = component;
}
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(() -> {
File file = null;
JFileChooser chooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
Logging.logInfo("Thread: " + Thread.currentThread().getName());
JFileChooser chooser = new JFileChooser();
chooser.setPreferredSize(new Dimension(800, 700));
chooser.setFileFilter(new FileNameExtensionFilter("Comma-Separated Value, (*.csv)", "csv", "text"));
chooser.setMultiSelectionEnabled(false);
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
if (chooser.showOpenDialog(component) == JFileChooser.APPROVE_OPTION) {
File file = null;
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
//Logging.logInfo ("Datei "+chooser.getSelectedFile()+ " ausgewählt.");
file = chooser.getSelectedFile();
final File input = file;
@ -53,5 +51,6 @@ public class ImportDataListener implements ActionListener {
t.start();
}
});
}
}

View File

@ -4,7 +4,6 @@ import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.presenter.Presenter;
import de.wwwu.awolf.presenter.algorithms.Algorithm;
import de.wwwu.awolf.presenter.data.DataProvider;
import de.wwwu.awolf.presenter.util.Logging;
import de.wwwu.awolf.view.MainFrame;
import de.wwwu.awolf.view.custom.ButtonGroupAtLeastTwo;

View File

@ -1,5 +1,5 @@
# Root logger option
log4j.rootLogger=INFO, file, stdout
log4j.rootLogger=DEBUG, file, stdout
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=D:\\Git\\master-implementierung\\LinearRegressionTool\\log4j\\app.log

View File

@ -23,7 +23,6 @@ import static org.junit.Assert.*;
public class LeastMedianOfSquaresEstimatorTest {
private LeastMedianOfSquaresEstimator lms;
private IntersectionComputer intersectionComputer;
@Before
public void setUp(){
@ -32,15 +31,12 @@ public class LeastMedianOfSquaresEstimatorTest {
LinkedList<Line> lines = new LinkedList<>();
ArrayList<Point> intersections = new ArrayList<>();
for (int i = 0; i < 5; i++) {
lines.add(new Line(x[i], y[i]));
}
intersectionComputer = new IntersectionComputer(lines);
intersections = intersectionComputer.compute();
lms = new LeastMedianOfSquaresEstimator(lines, intersections);
lms = new LeastMedianOfSquaresEstimator(lines);
}

View File

@ -23,7 +23,6 @@ import static org.junit.Assert.*;
public class TheilSenEstimatorTest {
TheilSenEstimator estimator;
IntersectionComputer intersectionComputer;
@Before
public void setUp(){
@ -32,15 +31,12 @@ public class TheilSenEstimatorTest {
List<Line> lines = new LinkedList<>();
List<Point> intersections = new ArrayList<>();
for (int i = 0; i < 5; i++) {
lines.add(new Line(x[i], y[i]));
}
intersectionComputer = new IntersectionComputer(lines);
intersections = intersectionComputer.compute();
estimator = new TheilSenEstimator(lines, intersections);
estimator = new TheilSenEstimator(lines);
}

View File

@ -1,58 +0,0 @@
package de.wwwu.awolf.presenter.util;
import de.wwwu.awolf.model.Line;
import de.wwwu.awolf.model.LineModel;
import de.wwwu.awolf.model.Point;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.*;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
*
* @Author: Armin Wolf
* @Email: a_wolf28@uni-muenster.de
* @Date: 23.10.2017.
*/
public class IntersectionComputerTest {
private IntersectionComputer intersectionComputer;
private LineModel lineModel;
@Before
public void setUp() throws Exception {
lineModel = new LineModel();
lineModel.addLine(new Line(3,13,10,3));
lineModel.addLine(new Line(1,9,1,9));
lineModel.addLine(new Line(1,12,4,6));
intersectionComputer = new IntersectionComputer(lineModel.getLines());
}
@Test
public void compute() throws Exception {
List<Point> intersections = intersectionComputer.compute();
double[] expectedX = {4.66, 7.11, 9.39};
double[] expectedY = {4.66, 7.11, 5.52};
double[] actualX = new double[3];
double[] actualY = new double[3];
for (int i=0;i<3;i++){
actualX[i] = intersections.get(i).getX();
actualY[i] = intersections.get(i).getY();
}
Arrays.sort(expectedX);
Arrays.sort(actualX);
assertArrayEquals(expectedX, actualX, 0.01d);
Arrays.sort(expectedY);
Arrays.sort(actualY);
assertArrayEquals(expectedY, actualY, 0.01d);
}
}