TS angefangen (Algorithmus Matousek)

This commit is contained in:
Armin Wolf 2017-06-26 16:01:54 +02:00
parent aedf31d746
commit 3c9f1b4628
10 changed files with 436 additions and 32 deletions

View File

@ -3,8 +3,7 @@ package Presenter.Algorithms;
import Model.Line;
import Model.Point;
import Model.Slab;
import Presenter.InversionCounter;
import Presenter.Presenter;
import Presenter.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -27,7 +26,7 @@ public class LeastMedianOfSquaresEstimator extends Observable implements Algorit
private LinkedList<Line> set = new LinkedList<>();
private LinkedList<Point> intersections = new LinkedList<>();
private InversionCounter invCounter = new InversionCounter();
private IntersectionCounter invCounter = new IntersectionCounter();
private int n;
private double quantileError;
private int kPlus;

View File

@ -2,8 +2,7 @@ package Presenter.Algorithms;
import Model.Line;
import Model.Slab;
import Presenter.InversionCounter;
import Presenter.Presenter;
import Presenter.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -80,10 +79,8 @@ public class RepeatedMedianEstimator extends Observable implements Algorithm {
while (linesInCenterSlab.size() != 1) {
n = linesInCenterSlab.size();
r = Math.ceil(Math.pow(n, beta));
ArrayList<Line> lines = sampleLines(linesInCenterSlab, r);
ArrayList<Line> lines = RandomLineSampler.run(linesInCenterSlab, r, linesInCenterSlab.size());
InversionCounter invCounter = new InversionCounter();
//int intersectionCount = invCounter.run(lines, interval);
//For each Sampled Line, compute its median intersection abscissa
ArrayList<Double> medianIntersectionAbscissas = new ArrayList<>();
@ -100,8 +97,8 @@ public class RepeatedMedianEstimator extends Observable implements Algorithm {
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");
// 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);
@ -156,18 +153,8 @@ public class RepeatedMedianEstimator extends Observable implements Algorithm {
ArrayList<Double> intersections = new ArrayList<>();
double intersection;
for (Line line : linesInCenterSlab) {
if (line != sampledLine) {
intersection = (line.getB() - sampledLine.getB()) / (sampledLine.getM() - line.getM());
if (!intersectionAbscissas.get(line).contains(intersection))
intersectionAbscissas.get(line).add(intersection);
if (!intersectionAbscissas.get(sampledLine).contains(intersection))
intersectionAbscissas.get(sampledLine).add(intersection);
intersections.add(intersection);
}
}
IntersectionCounter intersectionCounter = new IntersectionCounter();
intersections = intersectionCounter.calculateIntersectionAbscissas(linesInCenterSlab, sampledLine);
Collections.sort(intersections);
double ki = Math.ceil((n - 1) / 2) - countLeftSlab.get(index);

View File

@ -1,5 +1,16 @@
package Presenter.Algorithms;
import Model.Line;
import Model.Point;
import Model.Slab;
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.concurrent.ThreadLocalRandom;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
*
@ -7,6 +18,121 @@ package Presenter.Algorithms;
* @Email: a_wolf28@uni-muenster.de
* @Date: 28.05.2017.
*/
public class TheilSenEstimator implements Algorithm {
public class TheilSenEstimator extends Observable implements Algorithm {
private Presenter presenter;
private ArrayList<Line> set;
private ArrayList<Point> intersectionSet;
private Integer numberOfLinesOnLeft;
private Slab interval;
private Double j;
private Integer jA;
private Integer jB;
private Double r;
private Integer n;
private Double N;
private Integer k;
private Double a;
private Double b;
private Double aVariant;
private Double bVariant;
private ArrayList<Double> sampledIntersections;
private Double ymin = Double.MAX_VALUE;
private Double ymax = Double.MIN_VALUE;
public TheilSenEstimator(LinkedList<Line> set, LinkedList<Point> intersectionSet, Presenter presenter) {
this.presenter = presenter;
this.intersectionSet = new ArrayList<>(intersectionSet);
this.set = new ArrayList<>(set);
this.n = set.size();
this.sampledIntersections = new ArrayList<>();
Double bin = BinomialCoeffizient.run(n, 2);
this.numberOfLinesOnLeft = 0;
for (Line l : set){
ymin = ymin > l.getB() ? l.getB() : ymin;
ymax = ymax < l.getB() ? l.getB() : ymax;
}
this.k = Integer.valueOf((int) (bin / 2));
this.N = bin;
}
public void run(){
a = -10000d;
b = 10000d;
interval = new Slab(a,b);
while (true){
if (this.N <= n){
break;
} else {
r = Double.valueOf(n);
IntersectionCounter counter = new IntersectionCounter();
int numberOfIntersections = counter.run(set, new Slab(-10000,a));
j = (r /N) * (k - numberOfIntersections);
jA = (int) Math.floor(j - (3 * Math.sqrt(r)));
jB = (int) Math.floor(j + (3 * Math.sqrt(r)));
do {
sampledIntersections = randomSampleOfIntersections(intersectionSet, r);
Collections.sort(sampledIntersections);
aVariant = sampledIntersections.get(jA);
bVariant = sampledIntersections.get(jB);
}
while (!checkCondition(sampledIntersections));
a = aVariant;
b = bVariant;
N = Double.valueOf(checkNumberOfIntersectionInInterval(a,b,sampledIntersections));
}
}
if (presenter != null) {
setChanged();
double m = (interval.getLower() + interval.getUpper()) * (-0.5);
double min = Collections.min(sampledIntersections);
double max = Collections.max(sampledIntersections);
double avgx = (min + max) *0.5;
double avgy = (ymin + ymax) * 0.5;
double b = ((avgx * m) + avgy);
String[] result = {"rm", m+"", b+""};
notifyObservers(result);
}
System.out.println(interval.getLower()+" <=> "+interval.getUpper());
}
private Boolean checkCondition(ArrayList<Double> intersections){
Boolean cond1 = (intersections.get(k) >= aVariant) && (intersections.get(k) < bVariant);
Boolean cond2 = (checkNumberOfIntersectionInInterval(aVariant,bVariant,intersections) <= ((11 * N) / Math.sqrt(r)));
return cond1 && cond2;
}
public ArrayList<Double> randomSampleOfIntersections(ArrayList<Point> set, Double r){
ArrayList<Double> sampledLines = new ArrayList<>();
for (int i = 0; i < r; i++) {
sampledLines.add(set.get(ThreadLocalRandom.current().nextInt(0, set.size()-1)).getX());
}
return sampledLines;
}
public int checkNumberOfIntersectionInInterval(double a, double b, ArrayList<Double> intersections){
int counter = 0;
for (Double x : intersections){
if (x >= a && x < b){
counter++;
}
}
return counter;
}
}

View File

@ -0,0 +1,28 @@
package Presenter;
import java.util.Collections;
import java.util.LinkedList;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
*
* @Author: Armin Wolf
* @Email: a_wolf28@uni-muenster.de
* @Date: 26.06.2017.
*/
public class BinomialCoeffizient {
public static Double run(int n, int k) {
int res = 1;
if ( k > n - k )
k = n - k;
for (int i = 0; i < k; ++i){
res *= (n - i);
res /= (i + 1);
}
return Double.valueOf(res);
}
}

View File

@ -8,7 +8,9 @@ import Presenter.Comparators.YOrderLineComparatorEnd;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.jfree.xml.factory.objects.DoubleObjectDescription;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
@ -17,7 +19,7 @@ import java.util.List;
* @Email: a_wolf28@uni-muenster.de
* @Date: 18.06.2017.
*/
public class InversionCounter {
public class IntersectionCounter {
private HashMap<Integer, Integer> dictionaryTO;
private HashMap<Integer, Integer> dictionaryBACK;
@ -53,8 +55,6 @@ public class InversionCounter {
int ret = countInversions(substituted, 0, substituted.size() - 1, temp);
getIntersectionAbscissas();
return ret;
}
@ -150,7 +150,7 @@ public class InversionCounter {
}
public HashMap<Line, ArrayList<Line>> getIntersectionAbscissas() {
public HashMap<Line, ArrayList<Line>> getIntersectionLinePairs() {
ArrayList<Pair> result = new ArrayList<>();
HashMap<Line, ArrayList<Line>> ret = new HashMap<>();
@ -192,4 +192,44 @@ public class InversionCounter {
return ret;
}
public HashMap<Double,Double> calculateIntersectionAbscissas(){
ArrayList<Pair> result = new ArrayList<>();
HashMap<Double,Double> ret = new HashMap<>();
for (int i = 0; i < inversions.size(); i++) {
result.add(new Pair(dictionaryBACK.get(inversions.get(i).getP1()),
dictionaryBACK.get(inversions.get(i).getP2())));
}
ArrayList<Line> linePairs;
for (Pair p : result) {
Line line = secondaryDictionaryBACK.get(p.getP1());
Line sampledLine = secondaryDictionaryBACK.get(p.getP2());
if (!line.equals(sampledLine)){
double intersection = (line.getB() - sampledLine.getB()) / (sampledLine.getM() - line.getM());
ret.put(intersection, intersection);
}
}
return ret;
}
public ArrayList<Double> calculateIntersectionAbscissas(ArrayList<Line> set, Line sampledLine){
LinkedList<Line> lines = new LinkedList<>(set);
ArrayList<Double> intersections = new ArrayList<>();
double intersection;
for (Line line : lines) {
if (line != sampledLine) {
intersection = (line.getB() - sampledLine.getB()) / (sampledLine.getM() - line.getM());
intersections.add(intersection);
}
}
return intersections;
}
}

View File

@ -5,6 +5,7 @@ import Model.Line;
import Model.Point;
import Presenter.Algorithms.LeastMedianOfSquaresEstimator;
import Presenter.Algorithms.RepeatedMedianEstimator;
import Presenter.Algorithms.TheilSenEstimator;
import Presenter.Import.DataImporter;
import View.MainFrame;
import java.io.File;
@ -91,6 +92,16 @@ public class Presenter implements Observer {
});
}
if (result[0] == "ts"){
SwingUtilities.invokeLater(() -> {
getView().visualizeTS(Double.parseDouble(result[1]), Double.parseDouble(result[2]));
getView().logHeading("Theil-Sen Estimator");
getView().log("<b>m:</b> " + result[1]);
getView().log("<b>b:</b> " + result[2]);
getView().logSuccess("Berechnung wurde Erfolgreich durchgeführt <hr>");
});
}
if (result[0] == "import"){
Double max = Double.parseDouble(result[1]);
Double current = Double.parseDouble(result[2]);
@ -123,7 +134,7 @@ public class Presenter implements Observer {
if (input[0] != null && input[1] != null){
Double constant = Double.parseDouble(input[0]);
Double error = Double.parseDouble(input[1]);
lms = new LeastMedianOfSquaresEstimator(model.getLines(), model.getNodes(), this);
lms = new LeastMedianOfSquaresEstimator(getModel().getLines(), getModel().getNodes(), this);
lms.setConstant(constant);
lms.setQuantileError(error);
lms.addObserver(this);
@ -133,7 +144,7 @@ public class Presenter implements Observer {
public void calculateRM(String input){
if (input != null){
RepeatedMedianEstimator rm = new RepeatedMedianEstimator(this.getLines(), this);
RepeatedMedianEstimator rm = new RepeatedMedianEstimator(getModel().getLines(), this);
Double parameter = Double.parseDouble(input);
rm.setBeta(parameter);
rm.addObserver(this);
@ -141,6 +152,15 @@ public class Presenter implements Observer {
}
}
public void calculateTS(String input){
if (input != null){
TheilSenEstimator ts = new TheilSenEstimator(getModel().getLines(), getModel().getNodes(),this);
ts.addObserver(this);
ts.run();
}
}
/***************************************************************************************************************************
* Hilfsmethoden
***************************************************************************************************************************/

View File

@ -0,0 +1,47 @@
package Presenter;
import Model.Line;
import Model.Point;
import Model.Slab;
import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
*
* @Author: Armin Wolf
* @Email: a_wolf28@uni-muenster.de
* @Date: 26.06.2017.
*/
public class RandomLineSampler {
/**
*
* @param set
* @param r
* @return
*/
public static ArrayList<Line> run(ArrayList<Line> set, Double r, Integer indexOfEnd) {
ArrayList<Line> sampledLines = new ArrayList<>();
for (int i = 0; i < r; i++) {
sampledLines.add(set.get(ThreadLocalRandom.current().nextInt(0, indexOfEnd)));
}
return sampledLines;
}
/**
*
* @param set
* @param r
* @return
*/
public static ArrayList<Line> run(ArrayList<Line> set, Integer r) {
return run(set,Double.valueOf(r), set.size());
}
}

View File

@ -6,6 +6,7 @@ import View.Panels.LMSPanel;
import View.Panels.MenuPanel;
import View.Panels.OutputPanel;
import View.Panels.RMPanel;
import View.Panels.TSPanel;
import java.awt.BorderLayout;
import java.awt.ComponentOrientation;
import java.awt.Container;
@ -58,6 +59,7 @@ public class MainFrame extends JFrame {
private MenuPanel menupanel;
private LMSPanel lmsPanel;
private RMPanel rmPanel;
private TSPanel tsPanel;
private JPanel pane;
private JPanel northPanel;
@ -131,6 +133,12 @@ public class MainFrame extends JFrame {
createPlot(m,b,plotRM,rmPanel);
}
public void visualizeTS(double m, double b){
plotTS = new PlotDialog();
tsPanel.setPlotDialog(plotTS);
createPlot(m,b,plotTS, tsPanel);
}
public void createPlot(double m, double b, PlotDialog plot, JPanel panel){
SwingUtilities.invokeLater(() -> {
plot.clear();
@ -158,7 +166,7 @@ public class MainFrame extends JFrame {
private void setupTabbedPane() {
tabbedPane.add("Least Median of Squares", lmsPanel);
tabbedPane.add("Repeated Median", rmPanel);
tabbedPane.add("Theil-Sen", new JPanel());
tabbedPane.add("Theil-Sen", tsPanel);
}
private void addComponents() {
@ -196,6 +204,7 @@ public class MainFrame extends JFrame {
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
lmsPanel.setMinimumSize(new Dimension(400, 500));
rmPanel.setMinimumSize(new Dimension(400, 500));
tsPanel.setMinimumSize(new Dimension(400, 500));
output.setMinimumSize(new Dimension(400, 500));
progressDialog.setSize(300, 100);
}
@ -211,6 +220,7 @@ public class MainFrame extends JFrame {
pane = new JPanel();
lmsPanel = new LMSPanel();
rmPanel = new RMPanel();
tsPanel = new TSPanel();
menupanel = new MenuPanel();
northPanel = new JPanel();
@ -268,6 +278,14 @@ public class MainFrame extends JFrame {
}
});
tsPanel.getStartButton().addActionListener((ActionEvent e) -> {
if (tsPanel.getInput() != null){
Thread t = new Thread(
() -> this.getPresenter().calculateTS(tsPanel.getInput()));
t.start();
}
});
importButton.addActionListener((ActionEvent e) -> {
SwingUtilities.invokeLater(() -> {
File file = null;

View File

@ -0,0 +1,139 @@
package View.Panels;
import View.PlotDialog;
import com.sun.istack.internal.Nullable;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
/**
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
*
* @Author: Armin Wolf
* @Email: a_wolf28@uni-muenster.de
* @Date: 26.06.2017.
*/
public class TSPanel extends JPanel{
private JLabel labels;
private JTextField input;
private JButton startButton;
private JPanel continer;
private JPanel northPanel;
private JPanel centerPanel;
private PlotDialog plotDialog;
private GridBagConstraints gbc;
public TSPanel() {
this.labels = new JLabel();
this.input = new JTextField();
this.setLayout(new BorderLayout());
this.northPanel = new JPanel(new BorderLayout());
this.centerPanel = new JPanel(new BorderLayout());
this.northPanel.setBorder(new TitledBorder("Konfiguration"));
this.centerPanel.setBorder(new TitledBorder("Visualisierung"));
this.continer = new JPanel();
this.continer.setLayout(new GridBagLayout());
this.gbc = new GridBagConstraints();
this.gbc.anchor = GridBagConstraints.NORTH;
this.gbc.fill = GridBagConstraints.HORIZONTAL;
addTextfieldAndInput(0, "\u00df (0 < \u00df < 1)", 0.5);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
this.startButton = new JButton("Start");
this.startButton.setFont(new Font("Verdana",Font.PLAIN, 16));
gbc.insets = new Insets(30, 0, 10, 0);
gbc.gridx = 0;
gbc.gridy = 2;
gbc.weightx = 0.05;
gbc.weighty = 0.05;
buttonPanel.add(startButton);
continer.add(buttonPanel, gbc);
this.northPanel.add(continer, BorderLayout.CENTER);
this.add(northPanel, BorderLayout.NORTH);
this.add(centerPanel, BorderLayout.CENTER);
}
private void addTextfieldAndInput(int row, String name, Double value) {
this.labels = new JLabel(name);
this.labels.setFont(new Font("SansSerif", Font.PLAIN, 13));
this.input = new JTextField();
this.input.setText("" + value);
gbc.insets = new Insets(0, 5, 0, 0);
gbc.gridx = 0;
gbc.gridy = row;
gbc.weightx = 0.05;
gbc.weighty = 0.05;
continer.add(this.labels, gbc);
gbc.gridx = 1;
gbc.gridy = row;
gbc.weightx = 0.9;
gbc.weighty = 0.05;
gbc.insets = new Insets(0, 0, 0, 5);
continer.add(this.input, gbc);
}
public JButton getStartButton() {
return startButton;
}
@Nullable
public String getInput() {
String input = "";
input = this.input.getText();
if (isNumeric(input))
return input;
else
JOptionPane.showMessageDialog(null, "Bitte geben Sie numerische Werte als Parameter an.","Fehler bei der Eingabe", JOptionPane.ERROR_MESSAGE);
return null;
}
public void setInput(JTextField input) {
this.input = input;
}
public PlotDialog getPlotDialog() {
return plotDialog;
}
public void setPlotDialog(PlotDialog plotDialog) {
this.plotDialog = plotDialog;
if (this.centerPanel.getComponents().length > 0)
this.centerPanel.remove(0);
this.centerPanel.add(plotDialog, BorderLayout.CENTER);
this.plotDialog.setVisible(true);
this.repaint();
this.revalidate();
}
public boolean isNumeric(String str) {
try{
double d = Double.parseDouble(str);
}
catch(NumberFormatException nfe){
return false;
}
return true;
}
}

View File

@ -8,7 +8,7 @@ import static org.junit.Assert.assertTrue;
import Model.Line;
import Model.Point;
import Model.Slab;
import Presenter.InversionCounter;
import Presenter.IntersectionCounter;
import java.util.ArrayList;
import java.util.LinkedList;
import org.junit.Before;
@ -63,7 +63,7 @@ public class LeastMedianOfSquaresEstimatorTest {
for (double d : umax) {
b.add((int) d);
}
InversionCounter invCounter = new InversionCounter();
IntersectionCounter invCounter = new IntersectionCounter();
int ret = invCounter.run(a, b);
assertEquals(3d, ret, 0.001);