package presenter.evaluation; import model.Line; import model.LineModel; import model.Point; import presenter.algorithms.advanced.LeastMedianOfSquaresEstimator; import presenter.algorithms.advanced.RepeatedMedianEstimator; import presenter.algorithms.advanced.TheilSenEstimator; import presenter.algorithms.naiv.NaivLeastMedianOfSquaresEstimator; import presenter.algorithms.naiv.NaivRepeatedMedianEstimator; import presenter.algorithms.naiv.NaivTheilSenEstimator; import presenter.util.IntersectionComputer; import presenter.generator.DatasetGenerator; import presenter.io.DataImporter; import java.io.File; import java.util.ArrayList; import java.util.LinkedList; import java.util.Observable; /** * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. * * @Author: Armin Wolf * @Email: a_wolf28@uni-muenster.de * @Date: 01.08.2017. */ public class EvaluateAlgorithms extends Observable { private LineModel arrangement; private LinkedList lmsL; private LinkedList rmL; private LinkedList tsL; private ArrayList lmsP; private ArrayList tsP; private Thread lmsThread; private Thread rmThread; private Thread tsThread; private Double[] tsRes = new Double[2]; private Double[] rmRes = new Double[2]; private Double[] lmsRes = new Double[2]; private DatasetGenerator generator; private String[][] names = {{"MSE", "RMSE", "MAE", "MDAE", "Steigung", "y-Achsenabschnitt", "S-MSE", "S-RMSE", "S-MAE", "S-MDAE", "Brute-force Steigung", "Brute-force y-Achsenabschnitt"}, {"MAPE", "MDAPE", "RMSPE", "RMDSPE", "Steigung", "y-Achsenabschnitt"}}; //übergebene Parameter private int type; private int iterations; private int alg; /** * Konstruktor zur evaluation * * @param type Typ der evaluation * @param n Größe des Datensatzes * @param alg 0 = lms, * 1 = rm, * 2 = ts, * 3 = lms, rm, * 4 = lms, ts, * 5 = rm, ts, * 6 = lms, rm, ts, * @param datasettyp typ der zu generierenden Datensatz */ public EvaluateAlgorithms(int type, int n, int alg, String datasettyp) { this.arrangement = new LineModel(); generator = new DatasetGenerator(); switch (datasettyp) { case "Punktwolke": arrangement.setLines(generator.generateDataCloud(n)); break; case "Gerade": arrangement.setLines(generator.generateDataLines(n)); break; case "Kreis und Gerade": arrangement.setLines(generator.generateCircle(n)); break; } this.type = type; this.iterations = n; this.alg = alg; //IntersectionCounter counter = new IntersectionCounter(); //counter.run(arrangement.getLines(), new Interval(-99999, 99999)); //counter.calculateIntersectionAbscissas(arrangement); IntersectionComputer computer = new IntersectionComputer(arrangement.getLines()); arrangement.setNodes(computer.compute()); lmsL = new LinkedList<>(arrangement.getLines()); rmL = new LinkedList<>(arrangement.getLines()); tsL = new LinkedList<>(arrangement.getLines()); lmsP = new ArrayList<>(arrangement.getNodes()); tsP = new ArrayList<>(arrangement.getNodes()); } /** * Konstruktor zur evaluation * * @param type Typ der evaluation * @param alg 0 = lms, * 1 = rm, * 2 = ts, * 3 = lms, rm, * 4 = lms, ts, * 5 = rm, ts, * 6 = lms, rm, ts, * @param file Datei die importiert werden soll */ public EvaluateAlgorithms(int type, int alg, File file) { this.arrangement = new LineModel(); DataImporter importer = new DataImporter(file); LinkedList importedLines = importer.run(); if (importedLines != null) arrangement.setLines(importedLines); this.type = type; this.alg = alg; //IntersectionCounter counter = new IntersectionCounter(); //counter.run(arrangement.getLines(), new Interval(-99999, 99999)); //counter.calculateIntersectionAbscissas(arrangement); IntersectionComputer computer = new IntersectionComputer(arrangement.getLines()); arrangement.setNodes(computer.compute()); lmsL = new LinkedList<>(arrangement.getLines()); rmL = new LinkedList<>(arrangement.getLines()); tsL = new LinkedList<>(arrangement.getLines()); lmsP = new ArrayList<>(arrangement.getNodes()); tsP = new ArrayList<>(arrangement.getNodes()); } /** * Startet die Evaluation zu den passenden Typ. Bei beendigung wird der Beobachter informiert. * @throws InterruptedException */ public void run() { setChanged(); String[] msg = {"eval-dataset-generated"}; notifyObservers(msg); ArrayList result; ArrayList> multipleResults = new ArrayList<>(); switch (type) { case 0: //der alg der gewählt wurde if (alg == 0) { final double[] m = new double[1]; final double[] b = new double[1]; Thread t = new Thread(() -> { NaivLeastMedianOfSquaresEstimator l = new NaivLeastMedianOfSquaresEstimator(arrangement.getLines()); l.run(); m[0] = l.getM(); b[0] = l.getB(); }); t.start(); try { startLMS(); t.join(); } catch (InterruptedException e) { e.printStackTrace(); } result = getScaleDependentMeasure(arrangement.getLines(), lmsRes[0], lmsRes[1]); result.addAll(getScaledErrorBasedMeasure(arrangement.getLines(), lmsRes[0], lmsRes[1], m[0], b[0])); Double[] tmp = {lmsRes[0], lmsRes[1], m[0], b[0]}; sendPlotLineResults(tmp, 0); } else if (alg == 1) { final double[] m = new double[1]; final double[] b = new double[1]; Thread t = new Thread(() -> { NaivRepeatedMedianEstimator r = new NaivRepeatedMedianEstimator(arrangement.getLines()); r.run(); m[0] = r.getM(); b[0] = r.getB(); }); t.start(); try { startRM(); } catch (InterruptedException e) { e.printStackTrace(); } result = getScaleDependentMeasure(arrangement.getLines(), rmRes[0], rmRes[1]); result.addAll(getScaledErrorBasedMeasure(arrangement.getLines(), rmRes[0], rmRes[1], m[0], b[0])); Double[] tmp = {rmRes[0], rmRes[1], m[0], b[0]}; sendPlotLineResults(tmp, 1); } else { final double[] m = new double[1]; final double[] b = new double[1]; Thread t = new Thread(() -> { NaivTheilSenEstimator ts = new NaivTheilSenEstimator(arrangement.getLines()); ts.run(); m[0] = ts.getM(); b[0] = ts.getB(); }); t.start(); try { startTS(); } catch (InterruptedException e) { e.printStackTrace(); } result = getScaleDependentMeasure(arrangement.getLines(), tsRes[0], tsRes[1]); result.addAll(getScaledErrorBasedMeasure(arrangement.getLines(), tsRes[0], tsRes[1], m[0], b[0])); Double[] tmp = {tsRes[0], tsRes[1], m[0], b[0]}; sendPlotLineResults(tmp, 2); } sendTableApproximationTypes(); sendTableApproximationData(result, alg); break; case 1: ArrayList lineRes; switch (alg) { case 3: try { startLMS(); startRM(); } catch (InterruptedException e) { e.printStackTrace(); } result = getPercentigeErrorBasedMeasure(arrangement.getLines(), lmsRes[0], lmsRes[1]); multipleResults.add(result); result = getPercentigeErrorBasedMeasure(arrangement.getLines(), rmRes[0], rmRes[1]); multipleResults.add(result); result = fillPseudoResults(); multipleResults.add(result); lineRes = new ArrayList<>(); lineRes.add(lmsRes); lineRes.add(rmRes); sendPloteLineResults(lineRes, new Integer[]{0, 1}); break; case 4: try { startLMS(); startTS(); } catch (InterruptedException e) { e.printStackTrace(); } result = getPercentigeErrorBasedMeasure(arrangement.getLines(), lmsRes[0], lmsRes[1]); multipleResults.add(result); result = fillPseudoResults(); multipleResults.add(result); result = getPercentigeErrorBasedMeasure(arrangement.getLines(), tsRes[0], tsRes[1]); multipleResults.add(result); lineRes = new ArrayList<>(); lineRes.add(lmsRes); lineRes.add(tsRes); sendPloteLineResults(lineRes, new Integer[]{0, 2}); break; case 5: try { startRM(); startTS(); } catch (InterruptedException e) { e.printStackTrace(); } result = fillPseudoResults(); multipleResults.add(result); result = getPercentigeErrorBasedMeasure(arrangement.getLines(), rmRes[0], rmRes[1]); multipleResults.add(result); result = getPercentigeErrorBasedMeasure(arrangement.getLines(), tsRes[0], tsRes[1]); multipleResults.add(result); lineRes = new ArrayList<>(); lineRes.add(rmRes); lineRes.add(tsRes); sendPloteLineResults(lineRes, new Integer[]{1, 2}); break; case 6: try { startLMS(); startRM(); startTS(); } catch (InterruptedException e) { e.printStackTrace(); } result = getPercentigeErrorBasedMeasure(arrangement.getLines(), lmsRes[0], lmsRes[1]); multipleResults.add(result); result = getPercentigeErrorBasedMeasure(arrangement.getLines(), rmRes[0], rmRes[1]); multipleResults.add(result); result = getPercentigeErrorBasedMeasure(arrangement.getLines(), tsRes[0], tsRes[1]); multipleResults.add(result); lineRes = new ArrayList<>(); lineRes.add(lmsRes); lineRes.add(rmRes); lineRes.add(tsRes); sendPloteLineResults(lineRes, new Integer[]{0, 1, 2}); break; } sendTableApproximationData(multipleResults); break; } } /** * Die berechneten Ergebnisse werden an den Beobachter übermittelt um dann visualisiert zu werden. * @param result Ergebnisse * @param col Spalte */ public void sendTableApproximationData(ArrayList result, int col) { ArrayList tableInput = new ArrayList<>(); tableInput.add("eval-d"); tableInput.add("" + col); for (int i = 0; i < names[type].length; i++) { tableInput.add(result.get(i)); } tableInput.add(""); setChanged(); notifyObservers(tableInput.stream().toArray(String[]::new)); tableInput.clear(); } /** * Die berechneten Ergebnisse werden an den Beobachter übermittelt um dann visualisiert zu werden. * @param result Ergebnisse */ public void sendTableApproximationData(ArrayList> result) { ArrayList tableInput = new ArrayList<>(); //iteration über die ApproximationsGüten -- Zeilen for (int j = 0; j <= result.get(0).size(); j++) { tableInput.add("eval-ds"); if (j != result.get(0).size()) { tableInput.add(names[type][j]); //iteration über die alg. -- Spalten for (int i = 0; i < 3; i++) { tableInput.add(result.get(i).get(j)); } } else { tableInput.add(""); tableInput.add(""); tableInput.add(""); tableInput.add(""); } setChanged(); notifyObservers(tableInput.stream().toArray(String[]::new)); tableInput.clear(); } } /** * Die Art der Ergebnisse (MSE, RMSE,...) wird an der Beobachter übermittelt. */ public void sendTableApproximationTypes() { ArrayList tableInput = new ArrayList<>(); tableInput.add("eval-t"); tableInput.add("" + 0); for (int i = 0; i < names[type].length; i++) { tableInput.add(names[type][i]); } tableInput.add(""); setChanged(); notifyObservers(tableInput.stream().toArray(String[]::new)); tableInput.clear(); } /** * Zur visualisierung der berechneten Geraden wird die Steigung und der y-Achsenabschnitt an den * Beobachter übermittelt. * @param res Feld mit den Werten für die Steigung und dern y-Achsenabschnitt * @param alg code für welchen Algorithmus sich die Werte beziehen */ public void sendPlotLineResults(Double[] res, int alg) { //visualisiere m,b ArrayList lines = new ArrayList<>(); lines.add("lines-res"); lines.add("" + alg); //lms res for (int i = 0; i < res.length; i++) { lines.add(res[i] + ""); } setChanged(); notifyObservers(lines.stream().toArray(String[]::new)); } /** * Zur visualisierung der berechneten Geraden wird die Steigung und der y-Achsenabschnitt an den * Beobachter übermittelt. * @param res Feld mit den Werten für die Steigung und dern y-Achsenabschnitt (alle) * @param algs codes für welchen Algorithmus sich die Werte beziehen (alle) */ public void sendPloteLineResults(ArrayList res, Integer[] algs) { ArrayList lines = new ArrayList<>(); lines.add("lines-res-mult"); for (int i = 0; i < algs.length; i++) { lines.add("" + algs[i]); //lms res Double[] tmp = res.get(i); lines.add(tmp[0] + ""); lines.add(tmp[1] + ""); } setChanged(); notifyObservers(lines.stream().toArray(String[]::new)); } /** * Startet die Berechnung des Alg. zum LMS-Schätzer * @throws InterruptedException */ public void startLMS() throws InterruptedException { lmsThread = new Thread(() -> { LeastMedianOfSquaresEstimator lmsAlg = new LeastMedianOfSquaresEstimator(lmsL, lmsP); lmsAlg.run(); lmsAlg.pepareResult(); lmsRes[0] = lmsAlg.getSlope(); lmsRes[1] = lmsAlg.getyInterception(); }); lmsThread.start(); lmsThread.join(); } /** * Startet die Berechnung des Alg. zum RM-Schätzer * @throws InterruptedException */ public void startRM() throws InterruptedException { rmThread = new Thread(() -> { RepeatedMedianEstimator rmAlg = new RepeatedMedianEstimator(rmL); rmAlg.run(); rmAlg.pepareResult(); rmRes[0] = rmAlg.getSlope(); rmRes[1] = rmAlg.getyInterception(); }); rmThread.start(); rmThread.join(); } /** * Startet die Berechnung des Alg. zum TS-Schätzer * @throws InterruptedException */ public void startTS() throws InterruptedException { tsThread = new Thread(() -> { TheilSenEstimator tsAlg = new TheilSenEstimator(tsL, tsP); tsAlg.run(); tsAlg.pepareResult(); tsRes[0] = tsAlg.getSlope(); tsRes[1] = tsAlg.getyInterception(); }); tsThread.start(); tsThread.join(); } /** * Startet die Berechnung der skalierungsabbhängigen Maße. * @param lines Liste der Geraden * @param m Steigung * @param b y-Achsenabschnitt * @return Liste mit den Ergebnissen, bereit zum visualisieren */ public ArrayList getScaleDependentMeasure(final LinkedList lines, final Double m, final Double b) { ScaleDependentMeasure scaleDependentMeasure = new ScaleDependentMeasure(lines, m, b); ArrayList ret = new ArrayList<>(); ret.add(scaleDependentMeasure.mse().toString()); ret.add(scaleDependentMeasure.rmse().toString()); ret.add(scaleDependentMeasure.mae().toString()); ret.add(scaleDependentMeasure.mdae().toString()); ret.add(m.toString()); ret.add(b.toString()); return ret; } /** * Startet die Berechnung der Maße die auf dem prozentualen Fehler basieren. * @param lines Liste der Geraden * @param m Steigung * @param b y-Achsenabschnitt * @return Liste mit den Ergebnissen, bereit zum visualisieren */ public ArrayList getPercentigeErrorBasedMeasure(final LinkedList lines, final Double m, final Double b) { PercentageErrorBasedMeasure percentageErrorBasedMeasure = new PercentageErrorBasedMeasure(lines, m, b); ArrayList ret = new ArrayList<>(); ret.add(percentageErrorBasedMeasure.mape().toString()); ret.add(percentageErrorBasedMeasure.mdape().toString()); ret.add(percentageErrorBasedMeasure.rmspe().toString()); ret.add(percentageErrorBasedMeasure.rmdspe().toString()); ret.add(m.toString()); ret.add(b.toString()); return ret; } /** * Startet die Berechnung der skalierungsunabbhängigen Maße. * @param lines Liste der Geraden * @param m Steigung * @param b y-Achsenabschnitt * @return Liste mit den Ergebnissen, bereit zum visualisieren */ public ArrayList getScaledErrorBasedMeasure(final LinkedList lines, final Double m, final Double b, final Double nM, final Double nB) { ScaledErrorBasedMeasure scaledErrorBasedMeasure = new ScaledErrorBasedMeasure(lines, m, b, nM, nB); ArrayList ret = new ArrayList<>(); ret.add(scaledErrorBasedMeasure.mse().toString()); ret.add(scaledErrorBasedMeasure.rmse().toString()); ret.add(scaledErrorBasedMeasure.mae().toString()); ret.add(scaledErrorBasedMeasure.mdae().toString()); ret.add(nM.toString()); ret.add(nB.toString()); return ret; } /** * Damit es bei der Visualisierung trennende Zeilen gibt. * @return */ private ArrayList fillPseudoResults() { ArrayList result = new ArrayList<>(); result.add(" "); result.add(" "); result.add(" "); result.add(" "); result.add(" "); result.add(" "); return result; } /** * @return Liste der Geraden auf der die Berechnungen ausgeführt wurden */ public LinkedList getData() { return arrangement.getLines(); } }