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.DataHandler; 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.Logging; import java.io.File; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; 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 EvaluatationHandler 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 EvaluatationHandler(int type, int n, int alg, DataHandler.DataType datasettyp) { Presenter instance = Presenter.getInstance(); subscribe(instance); this.arrangement = new LineModel(); this.resultMapping = new EnumMap<>(Algorithm.Type.class); Set data = instance.generateDataset(n, datasettyp); 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; } /** * 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 EvaluatationHandler(int type, int alg, File file) { Presenter instance = Presenter.getInstance(); subscribe(instance); instance.importDataset(file); this.arrangement = instance.getModel(); this.resultMapping = new EnumMap<>(Algorithm.Type.class); this.type = type; this.alg = alg; } 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.unmodifiableSet(arrangement.getLines())); 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.unmodifiableSet(arrangement.getLines())); ComparisonResult comparisonResult = comparison.compare(); types.forEach(typeEntry -> this.resultMapping.put(typeEntry, getPercentigeErrorBasedMeasure(arrangement.getLines(), comparisonResult, typeEntry))); 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.NAIVE_LMS); } else if (alg == 1) { result = benchmarkSameEstimator(Algorithm.Type.RM, Algorithm.Type.NAIVE_RM); } else { result = benchmarkSameEstimator(Algorithm.Type.TS, Algorithm.Type.NAIVE_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 Set 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 Set 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 Set 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 Set getData() { return arrangement.getLines(); } @Override public void subscribe(Flow.Subscriber subscriber) { this.subscriber = subscriber; } }