package de.wwwu.awolf.presenter.evaluation; import de.wwwu.awolf.model.Line; import de.wwwu.awolf.model.LineModel; import de.wwwu.awolf.model.communication.Data; import de.wwwu.awolf.model.communication.EvaluationData; import de.wwwu.awolf.model.communication.SubscriberType; import de.wwwu.awolf.model.evaluation.ComparisonResult; 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.data.generator.DatasetGenerator; import de.wwwu.awolf.presenter.evaluation.measures.PercentageErrorBasedMeasure; import de.wwwu.awolf.presenter.evaluation.measures.ScaleDependentMeasure; import de.wwwu.awolf.presenter.evaluation.measures.ScaledErrorBasedMeasure; import de.wwwu.awolf.presenter.util.IntersectionComputer; import de.wwwu.awolf.presenter.util.Logging; import java.io.File; import java.util.*; import java.util.concurrent.Flow; /** * Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden. * * @Author: Armin Wolf * @Email: a_wolf28@uni-muenster.de * @Date: 01.08.2017. */ public class EvaluateAlgorithms implements Runnable, Flow.Publisher { private LineModel arrangement; private DatasetGenerator generator; //übergebene Parameter private int type; private int iterations; private int alg; private Flow.Subscriber subscriber; private Map> resultMapping; /** * 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, DataProvider.DataType datasettyp, Presenter presenter) { subscribe(presenter); this.arrangement = new LineModel(); this.resultMapping = new EnumMap<>(Algorithm.Type.class); List data = presenter.getDataProvider().getData(datasettyp, n); Logging.logInfo("Starting the Benchmark..."); arrangement.setLines(data); Logging.logInfo("Benchmark on Dataset: " + datasettyp + " with " + n + " points"); this.type = type; this.iterations = n; this.alg = alg; IntersectionComputer computer = new IntersectionComputer(arrangement.getLines()); arrangement.setNodes(computer.compute()); } /** * 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, Presenter presenter) { subscribe(presenter); presenter.startImport(file); this.arrangement = presenter.getModel(); this.resultMapping = new EnumMap<>(Algorithm.Type.class); this.type = type; this.alg = alg; IntersectionComputer computer = new IntersectionComputer(arrangement.getLines()); arrangement.setNodes(computer.compute()); } private Map> 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())); ComparisonResult comparisonResult = comparison.compare(); Map result = new HashMap<>(); result.putAll(getScaleDependentMeasure(arrangement.getLines(), comparisonResult, advanced)); result.putAll(getScaledErrorBasedMeasure(arrangement.getLines(), comparisonResult, advanced, naiv)); Logging.logInfo("finished with execution of the algorithms."); this.resultMapping.put(advanced, result); return this.resultMapping; } private Map> benchmarkDifferentEstimators(List types) { Logging.logInfo("AlgorithmComparison with Types: " + types); AlgorithmComparison comparison = new AlgorithmComparison(types, Collections.unmodifiableList(arrangement.getLines()), Collections.unmodifiableList(arrangement.getNodes())); ComparisonResult comparisonResult = comparison.compare(); Map multipleResults = new HashMap<>(); types.forEach(type -> this.resultMapping.put(type, getPercentigeErrorBasedMeasure(arrangement.getLines(), comparisonResult, type))); Logging.logInfo("finished with execution of the algorithms."); return this.resultMapping; } /** * Startet die Evaluation zu den passenden Typ. Bei beendigung wird der Beobachter informiert. */ @Override public void run() { Map> result = new EnumMap<>(Algorithm.Type.class); switch (type) { case 0: //der alg der gewählt wurde if (alg == 0) { result = benchmarkSameEstimator(Algorithm.Type.LMS, Algorithm.Type.NAIV_LMS); } else if (alg == 1) { result = benchmarkSameEstimator(Algorithm.Type.RM, Algorithm.Type.NAIV_RM); } else { result = benchmarkSameEstimator(Algorithm.Type.TS, Algorithm.Type.NAIV_TS); } break; case 1: switch (alg) { case 3: result = benchmarkDifferentEstimators(Arrays.asList(Algorithm.Type.LMS, Algorithm.Type.RM)); break; case 4: result = benchmarkDifferentEstimators(Arrays.asList(Algorithm.Type.LMS, Algorithm.Type.TS)); break; case 5: result = benchmarkDifferentEstimators(Arrays.asList(Algorithm.Type.RM, Algorithm.Type.TS)); break; case 6: result = benchmarkDifferentEstimators(Arrays.asList(Algorithm.Type.LMS, Algorithm.Type.RM, Algorithm.Type.TS)); break; } break; } sendTableApproximationData(result); } /** * Die berechneten Ergebnisse werden an den Beobachter übermittelt um dann visualisiert zu werden. * * @param result Ergebnisse */ private void sendTableApproximationData(Map> result) { EvaluationData data = new EvaluationData(); data.setType(SubscriberType.EVALUATION_TABLE_DATA); data.setMultipleColumnResult(result); data.setRowsPerColumn(result.keySet().size()); this.subscriber.onNext(data); } /** * Startet die Berechnung der skalierungsabbhängigen Maße. * * @param lines Liste der Geraden * @return Liste mit den Ergebnissen, bereit zum visualisieren */ private Map getScaleDependentMeasure(final List lines, final ComparisonResult comparisonResult, final Algorithm.Type type) { Logging.logInfo("Calculating ScaleDependentMeasure for " + type); Double m = comparisonResult.get(type).getM(); Double b = comparisonResult.get(type).getB(); ScaleDependentMeasure scaleDependentMeasure = new ScaleDependentMeasure(lines, m, b); Map ret = new HashMap<>(); ret.put(type + " MSE", scaleDependentMeasure.mse().toString()); ret.put(type + " RMSE", scaleDependentMeasure.rmse().toString()); ret.put(type + " MAE", scaleDependentMeasure.mae().toString()); ret.put(type + " MDAE", scaleDependentMeasure.mdae().toString()); ret.put(type + " SLOPE", m.toString()); ret.put(type + " y-INTERCEPTION", b.toString()); Logging.logInfo("finished calculating ScaleDependentMeasure."); return ret; } /** * Startet die Berechnung der Maße die auf dem prozentualen Fehler basieren. * * @param lines Liste der Geraden * @return Liste mit den Ergebnissen, bereit zum visualisieren */ private Map getPercentigeErrorBasedMeasure(final List lines, final ComparisonResult comparisonResult, final Algorithm.Type type) { Logging.logInfo("Calculating PercentigeErrorBasedMeasure for " + type); Double m = comparisonResult.get(type).getM(); Double b = comparisonResult.get(type).getB(); PercentageErrorBasedMeasure percentageErrorBasedMeasure = new PercentageErrorBasedMeasure(lines, m, b); Map ret = new HashMap<>(); ret.put(type + " MAPE", percentageErrorBasedMeasure.mape().toString()); ret.put(type + " MDAPE", percentageErrorBasedMeasure.mdape().toString()); ret.put(type + " RMSPE", percentageErrorBasedMeasure.rmspe().toString()); ret.put(type + " RMDSPE", percentageErrorBasedMeasure.rmdspe().toString()); ret.put(type + " SLOPE", m.toString()); ret.put(type + " y-INTERCEPTION", b.toString()); Logging.logInfo("finished calculating PercentigeErrorBasedMeasure."); return ret; } /** * Startet die Berechnung der skalierungsunabbhängigen Maße. * * @param lines Liste der Geraden * @return Liste mit den Ergebnissen, bereit zum visualisieren */ private Map getScaledErrorBasedMeasure(final List lines, final ComparisonResult comparisonResult, final Algorithm.Type advanced, final Algorithm.Type naiv) { Logging.logInfo("Calculating ScaledErrorBasedMeasure for " + advanced + ", " + naiv); //first Double m = comparisonResult.get(advanced).getM(); Double b = comparisonResult.get(advanced).getB(); //second Double naivM = comparisonResult.get(naiv).getM(); Double naivB = comparisonResult.get(naiv).getB(); ScaledErrorBasedMeasure scaledErrorBasedMeasure = new ScaledErrorBasedMeasure(lines, m, b, naivM, naivB); Map ret = new HashMap<>(); ret.put(advanced + " MSE", scaledErrorBasedMeasure.mse().toString()); ret.put(advanced + " RMSE", scaledErrorBasedMeasure.rmse().toString()); ret.put(advanced + " MAE", scaledErrorBasedMeasure.mae().toString()); ret.put(advanced + " MDAE", scaledErrorBasedMeasure.mdae().toString()); ret.put(advanced + " Naiv-SLOPE", naivM.toString()); ret.put(advanced + " Naiv-y-INTERCEPTION", naivB.toString()); Logging.logInfo("finished calculating ScaledErrorBasedMeasure."); return ret; } /** * @return Liste der Geraden auf der die Berechnungen ausgeführt wurden */ public List getData() { return arrangement.getLines(); } @Override public void subscribe(Flow.Subscriber subscriber) { this.subscriber = subscriber; } }