some refactoring
2
.gitignore
vendored
@ -15,7 +15,7 @@
|
||||
log/
|
||||
target/
|
||||
# Ignore Gradle project-specific cache directory
|
||||
.gradle
|
||||
.gradle/
|
||||
|
||||
# Ignore Gradle build output directory
|
||||
build
|
||||
|
41
build.gradle
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id "org.sonarqube" version "2.7"
|
||||
}
|
||||
|
||||
apply plugin: 'org.sonarqube'
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = uri('http://repo.maven.apache.org/maven2')
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'junit:junit:4.12'
|
||||
implementation 'commons-io:commons-io:2.5'
|
||||
implementation 'log4j:log4j:1.2.17'
|
||||
implementation 'org.apache.logging.log4j:log4j-core:2.13.1'
|
||||
implementation 'com.opencsv:opencsv:5.1'
|
||||
implementation 'com.google.guava:guava:28.2-jre'
|
||||
implementation 'org.powermock:powermock-core:2.0.6'
|
||||
compile group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'
|
||||
}
|
||||
|
||||
group = 'de.wwu.awolf'
|
||||
version = '1.0.0'
|
||||
sourceCompatibility = '11'
|
||||
|
||||
sonarqube {
|
||||
properties {
|
||||
property "sonar.projectName", "${rootProject.name}"
|
||||
property "sonar.projectKey", "${project.group}:${rootProject.name}"
|
||||
}
|
||||
}
|
||||
|
1
gradle.properties
Normal file
@ -0,0 +1 @@
|
||||
systemProp.sonar.host.url=http://192.168.0.158:9000
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#Wed Mar 25 19:04:29 CET 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
183
gradlew
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
103
gradlew.bat
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
4
settings.gradle
Normal file
@ -0,0 +1,4 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
rootProject.name = 'linreg-tool'
|
61
src/main/java/de/wwwu/awolf/App.java
Normal file
@ -0,0 +1,61 @@
|
||||
package de.wwwu.awolf;
|
||||
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import de.wwwu.awolf.view.ViewController;
|
||||
import de.wwwu.awolf.view.services.GuiRegisterService;
|
||||
import java.io.IOException;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 28.05.2017.
|
||||
*/
|
||||
public class App extends Application {
|
||||
|
||||
private static final String TITLE = "Algorithmen zur Berechnung von Ausgleichsgeraden";
|
||||
|
||||
/**
|
||||
* Maim Methode
|
||||
*
|
||||
* @param argv
|
||||
*/
|
||||
public static void main(String[] argv) {
|
||||
Logging.logDebug("Start ....");
|
||||
Application.launch(App.class, argv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
Platform.runLater(() -> {
|
||||
|
||||
try {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(
|
||||
ViewController.class.getResource("/views/MainFrame.fxml"));
|
||||
Parent pane = fxmlLoader.load();
|
||||
//register at presenter
|
||||
new GuiRegisterService(fxmlLoader.getController()).start();
|
||||
primaryStage.setTitle(TITLE);
|
||||
Scene scene = new Scene(pane, 1200, 900);
|
||||
scene.getStylesheets()
|
||||
.add(ViewController.class.getResource("/style/style.css")
|
||||
.toExternalForm());
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setOnCloseRequest(e -> {
|
||||
Platform.exit();
|
||||
System.exit(0);
|
||||
});
|
||||
primaryStage.show();
|
||||
} catch (IOException e) {
|
||||
Logging.logError("Error reading FXML file. ", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
79
src/main/java/de/wwwu/awolf/model/Interval.java
Normal file
@ -0,0 +1,79 @@
|
||||
package de.wwwu.awolf.model;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 16.06.2017.
|
||||
*/
|
||||
public class Interval {
|
||||
|
||||
private double upper;
|
||||
private double lower;
|
||||
private Boolean activity;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param lower untere Schranke
|
||||
* @param upper obere Schranke
|
||||
*/
|
||||
public Interval(double lower, double upper) {
|
||||
this.upper = upper;
|
||||
this.lower = lower;
|
||||
this.activity = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> falls das Intervall aktiv ist
|
||||
*/
|
||||
public Boolean getActivity() {
|
||||
return activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isActive <code>true</code> falls das Intervall als aktiv gesetzt werden soll
|
||||
*/
|
||||
public void setActivity(Boolean isActive) {
|
||||
this.activity = isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return obere Schranke des Intervalls
|
||||
*/
|
||||
public double getUpper() {
|
||||
return upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param upper obere Schranke des Intervalls
|
||||
*/
|
||||
public void setUpper(double upper) {
|
||||
this.upper = upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return untere Schranke des Intervalls
|
||||
*/
|
||||
public double getLower() {
|
||||
return lower;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lower untere Schranke des Intervalls
|
||||
*/
|
||||
public void setLower(double lower) {
|
||||
this.lower = lower;
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Distanz zwischen der oberen und unteren Schranke
|
||||
*
|
||||
* @return Distanz
|
||||
*/
|
||||
public Double getDistance() {
|
||||
return Math.abs(this.upper - this.lower);
|
||||
}
|
||||
|
||||
}
|
297
src/main/java/de/wwwu/awolf/model/Line.java
Normal file
@ -0,0 +1,297 @@
|
||||
package de.wwwu.awolf.model;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.apache.commons.math3.util.Precision;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 12.06.2017.
|
||||
*/
|
||||
public class Line implements Comparable<Line> {
|
||||
|
||||
private static final double EPSILON = 0.00001;
|
||||
private static final double MIN = 9999d;
|
||||
private static final double MAX = -9999d;
|
||||
|
||||
|
||||
private Double m;
|
||||
private Double b;
|
||||
|
||||
private Double x1;
|
||||
private Double x2;
|
||||
private Double y1;
|
||||
private Double y2;
|
||||
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param m Steigung
|
||||
* @param b y-Achsenabschnitt
|
||||
* @param id id
|
||||
*/
|
||||
public Line(double m, double b, String id) {
|
||||
this.m = m;
|
||||
this.b = b;
|
||||
|
||||
this.x1 = MAX;
|
||||
this.y1 = (MAX * m) + b;
|
||||
this.x2 = MIN * 0.5;
|
||||
this.y2 = ((MIN * 0.5) * m) + b;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param m Steigung
|
||||
* @param b y-Achsenabschnitt
|
||||
*/
|
||||
public Line(double m, double b) {
|
||||
this.m = m;
|
||||
this.b = b;
|
||||
|
||||
this.x1 = calculateX1(MAX);
|
||||
this.y1 = calculateY1(MAX);
|
||||
this.x2 = calculateX2(MIN * 0.5);
|
||||
this.y2 = calculateY2(MIN * 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param x1 x-Koordiante des Startpunkts
|
||||
* @param x2 x-Koordinate des Endpunkts
|
||||
* @param y1 y-Koordinate des Startpunkts
|
||||
* @param y2 y-Koordinate des Endpunkts
|
||||
*/
|
||||
public Line(double x1, double x2, double y1, double y2) {
|
||||
this.x1 = x1;
|
||||
this.x2 = x2;
|
||||
this.y1 = y1;
|
||||
this.y2 = y2;
|
||||
|
||||
this.m = (y2 - y1) / (x2 - x1);
|
||||
this.b = y2 - (x2 * m);
|
||||
|
||||
}
|
||||
|
||||
public Double calculateX1(Double min) {
|
||||
return min;
|
||||
}
|
||||
|
||||
public Double calculateY1(Double min) {
|
||||
return (min * (m * -1)) + b;
|
||||
}
|
||||
|
||||
public Double calculateX2(Double max) {
|
||||
return max;
|
||||
}
|
||||
|
||||
public Double calculateY2(Double max) {
|
||||
return (max * (m * -1)) + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Steigung der Gerade
|
||||
*/
|
||||
public Double getM() {
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param m Steigung der Gerade
|
||||
*/
|
||||
public void setM(double m) {
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Achsenabschnitt der Gerade
|
||||
*/
|
||||
public Double getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param b y-Achsenabschnitt der Gerade
|
||||
*/
|
||||
public void setB(double b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return id der Gerade
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id id der Gerade
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return x-Koordiante des Startpunkts
|
||||
*/
|
||||
public Double getX1() {
|
||||
return x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return x-Koordiante des Endpunkts
|
||||
*/
|
||||
public Double getX2() {
|
||||
return x2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Koordiante des Startpunkts
|
||||
*/
|
||||
public Double getY1() {
|
||||
return y1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Koordiante des Endpunkts
|
||||
*/
|
||||
public Double getY2() {
|
||||
return y2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die Koordianten des Segments. Aus dem Segment wird eine Gerade berechnet.
|
||||
*
|
||||
* @param x1 x-Koordiante des Startpunkts
|
||||
* @param y1 y-Koordiante des Endpunkts
|
||||
* @param x2 x-Koordinate des Startpunkts
|
||||
* @param y2 y-Koordinte des Endpunkts
|
||||
*/
|
||||
public void setEndPoints(double x1, double y1, double x2, double y2) {
|
||||
this.x1 = x1;
|
||||
this.x2 = x2;
|
||||
this.y1 = y1;
|
||||
this.y2 = y2;
|
||||
this.m = (y2 - y1) / (x2 - x1);
|
||||
this.b = y2 - (x2 * m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vergleich einzelner Geradern
|
||||
*
|
||||
* @param obj zu vergleichende Gerade
|
||||
* @return <code>true</code> falls die Geraden Gleich sind
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Line) {
|
||||
Line other = (Line) obj;
|
||||
return Precision.equals(other.getM(), this.getM(), EPSILON) && Precision
|
||||
.equals(other.getB(), this.getB(), EPSILON);
|
||||
} else {
|
||||
return super.equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(Precision.round(m, 5), Precision.round(b, 5));
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
return 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());
|
||||
}
|
||||
|
||||
// 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
|
||||
return o4 == 0 && onSegment(p2, q1, q2);// Doesn't fall in any of the above cases
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Line line) {
|
||||
if (Precision.compareTo(this.getM(), line.getM(), EPSILON) == 0) {
|
||||
return this.getB().compareTo(line.getB());
|
||||
} else {
|
||||
return this.getM().compareTo(line.getM());
|
||||
}
|
||||
}
|
||||
}
|
145
src/main/java/de/wwwu/awolf/model/LineModel.java
Normal file
@ -0,0 +1,145 @@
|
||||
package de.wwwu.awolf.model;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 28.05.2017.
|
||||
*/
|
||||
public class LineModel {
|
||||
|
||||
private Double max;
|
||||
private Double min;
|
||||
|
||||
private Set<Line> lines;
|
||||
private Double xMinimum;
|
||||
private Double xMaximum;
|
||||
private Double yMinimum;
|
||||
private Double yMaximum;
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*/
|
||||
public LineModel() {
|
||||
lines = new HashSet<>();
|
||||
size = 0;
|
||||
|
||||
xMinimum = Double.MAX_VALUE;
|
||||
xMaximum = Double.MIN_VALUE;
|
||||
yMinimum = Double.MAX_VALUE;
|
||||
yMaximum = Double.MIN_VALUE;
|
||||
|
||||
min = 0d;
|
||||
max = 0d;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fügt eine Gerade zu dem Modell hinzu
|
||||
*
|
||||
* @param line Gerade
|
||||
*/
|
||||
public void addLine(Line line) {
|
||||
this.lines.add(line);
|
||||
min = line.getM() <= min ? line.getM() : min;
|
||||
max = line.getM() >= max ? line.getM() : max;
|
||||
}
|
||||
|
||||
public Double getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public Double getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Liste der Geraden
|
||||
*/
|
||||
public Set<Line> getLines() {
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lines Liste der Geraden
|
||||
*/
|
||||
public void setLines(Set<Line> lines) {
|
||||
lines.forEach(this::addLine);
|
||||
this.size = lines.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Minimale x-Koordiante
|
||||
*/
|
||||
public Double getxMinimum() {
|
||||
return xMinimum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param xMinimum Minimale x-Koordiante
|
||||
*/
|
||||
public void setxMinimum(Double xMinimum) {
|
||||
this.xMinimum = xMinimum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximale x-Koordiante
|
||||
*/
|
||||
public Double getxMaximum() {
|
||||
return xMaximum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param xMaximum Maximale x-Koordiante
|
||||
*/
|
||||
public void setxMaximum(Double xMaximum) {
|
||||
this.xMaximum = xMaximum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Minimale y-Koordiante
|
||||
*/
|
||||
public Double getyMinimum() {
|
||||
return yMinimum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param yMinimum Minimale y-Koordiante
|
||||
*/
|
||||
public void setyMinimum(Double yMinimum) {
|
||||
this.yMinimum = yMinimum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximale y-Koordiante
|
||||
*/
|
||||
public Double getyMaximum() {
|
||||
return yMaximum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param yMaximum Maximale y-Koordiante
|
||||
*/
|
||||
public void setyMaximum(Double yMaximum) {
|
||||
this.yMaximum = yMaximum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die minimalen, maximalen x- und y-Koordinaten
|
||||
*/
|
||||
public void resetRanges() {
|
||||
xMinimum = Double.MAX_VALUE;
|
||||
xMaximum = Double.MIN_VALUE;
|
||||
yMinimum = Double.MAX_VALUE;
|
||||
yMaximum = Double.MIN_VALUE;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
}
|
54
src/main/java/de/wwwu/awolf/model/Pair.java
Normal file
@ -0,0 +1,54 @@
|
||||
package de.wwwu.awolf.model;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 19.06.2017.
|
||||
*/
|
||||
public class Pair {
|
||||
|
||||
private Integer p1;
|
||||
private Integer p2;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param p1 erstes Element des Tupels
|
||||
* @param p2 zweites Element des Tupels
|
||||
*/
|
||||
public Pair(Integer p1, Integer p2) {
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return erstes Element des Tupels
|
||||
*/
|
||||
public Integer getP1() {
|
||||
return p1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param p1 erstes Element des Tupels
|
||||
*/
|
||||
public void setP1(Integer p1) {
|
||||
this.p1 = p1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return zweites Element des Tupels
|
||||
*/
|
||||
public Integer getP2() {
|
||||
return p2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param p2 zweites Element des Tupels
|
||||
*/
|
||||
public void setP2(Integer p2) {
|
||||
this.p2 = p2;
|
||||
}
|
||||
|
||||
}
|
119
src/main/java/de/wwwu/awolf/model/Point.java
Normal file
@ -0,0 +1,119 @@
|
||||
package de.wwwu.awolf.model;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.apache.commons.math3.util.Precision;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 28.05.2017.
|
||||
*/
|
||||
public class Point implements Comparable<Point> {
|
||||
|
||||
private static final double EPSILON = 0.00001;
|
||||
|
||||
private Double x;
|
||||
private Double y;
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param x x-Koordiante
|
||||
* @param y y-Koordiante
|
||||
*/
|
||||
public Point(Double x, Double y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param x x-Koordiante
|
||||
* @param y y-Koordiante
|
||||
* @param id id des Punkts
|
||||
*/
|
||||
public Point(Double x, Double y, String id) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return x-Koordinate des Punkts
|
||||
*/
|
||||
public Double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x x-Koordinate des Punkts
|
||||
*/
|
||||
public void setX(Double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Koordinate des Punkts
|
||||
*/
|
||||
public Double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param y y-Koordinate des Punkts
|
||||
*/
|
||||
public void setY(Double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Point o) {
|
||||
if (Precision.compareTo(this.getX(), o.getX(), EPSILON) == 0) {
|
||||
return this.getY().compareTo(o.getY());
|
||||
} else {
|
||||
return this.getX().compareTo(o.getX());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vergleich zweier Punkte
|
||||
*
|
||||
* @param obj zu vergleichernder Punkt
|
||||
* @return <code>true</code> falls die Punkte gleich sind
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Point) {
|
||||
Point other = (Point) obj;
|
||||
return Precision.equals(other.getX(), this.getX(), EPSILON) && Precision
|
||||
.equals(other.getY(), this.getY(), EPSILON);
|
||||
} else {
|
||||
return super.equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(Precision.round(x, 5), Precision.round(y, 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return id des Punkts
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id id des Punkts
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package de.wwwu.awolf.model.communication;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
|
||||
public class AlgorithmData implements Data {
|
||||
|
||||
private SubscriberType type;
|
||||
private Algorithm.Type algorithmType;
|
||||
private Line lineData;
|
||||
|
||||
public Algorithm.Type getAlgorithmType() {
|
||||
return algorithmType;
|
||||
}
|
||||
|
||||
public void setAlgorithmType(Algorithm.Type algorithmType) {
|
||||
this.algorithmType = algorithmType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriberType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(SubscriberType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Line getLineData() {
|
||||
return lineData;
|
||||
}
|
||||
|
||||
public void setLineData(Line lineData) {
|
||||
this.lineData = lineData;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package de.wwwu.awolf.model.communication;
|
||||
|
||||
public interface Data {
|
||||
|
||||
SubscriberType getType();
|
||||
|
||||
void setType(SubscriberType type);
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package de.wwwu.awolf.model.communication;
|
||||
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class EvaluationData implements Data {
|
||||
|
||||
private SubscriberType type;
|
||||
private List<Algorithm.Type> algorithmtypes;
|
||||
private List<Serializable> oneColumnresult;
|
||||
private Map<Algorithm.Type, Map<String, String>> multipleColumnResult;
|
||||
|
||||
private int rowsPerColumn;
|
||||
private int column;
|
||||
private List<String> labels;
|
||||
|
||||
public int getRowsPerColumn() {
|
||||
return rowsPerColumn;
|
||||
}
|
||||
|
||||
public void setRowsPerColumn(int rowsPerColumn) {
|
||||
this.rowsPerColumn = rowsPerColumn;
|
||||
}
|
||||
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
public void setColumn(int col) {
|
||||
this.column = col;
|
||||
}
|
||||
|
||||
public List<String> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
public void setLabels(List<String> tableInput) {
|
||||
this.labels = tableInput;
|
||||
}
|
||||
|
||||
public List<Algorithm.Type> getAlgorithmtypes() {
|
||||
return algorithmtypes;
|
||||
}
|
||||
|
||||
public void setAlgorithmtypes(List<Algorithm.Type> algorithmtype) {
|
||||
this.algorithmtypes = algorithmtype;
|
||||
}
|
||||
|
||||
public List<Serializable> getOneColumnresult() {
|
||||
return oneColumnresult;
|
||||
}
|
||||
|
||||
public void setOneColumnresult(List<Serializable> oneColumnresult) {
|
||||
this.oneColumnresult = oneColumnresult;
|
||||
}
|
||||
|
||||
public Map<Algorithm.Type, Map<String, String>> getMultipleColumnResult() {
|
||||
return multipleColumnResult;
|
||||
}
|
||||
|
||||
public void setMultipleColumnResult(
|
||||
Map<Algorithm.Type, Map<String, String>> multipleColumnResult) {
|
||||
this.multipleColumnResult = multipleColumnResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriberType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(SubscriberType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package de.wwwu.awolf.model.communication;
|
||||
|
||||
public class GeneratorData implements Data {
|
||||
|
||||
private SubscriberType type;
|
||||
private String message;
|
||||
private double m;
|
||||
private double b;
|
||||
|
||||
public double getM() {
|
||||
return m;
|
||||
}
|
||||
|
||||
public void setM(double m) {
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
public double getB() {
|
||||
return b;
|
||||
}
|
||||
|
||||
public void setB(double b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriberType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(SubscriberType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package de.wwwu.awolf.model.communication;
|
||||
|
||||
public class ImportData implements Data {
|
||||
|
||||
private SubscriberType type;
|
||||
private int numberOfLines;
|
||||
private int current;
|
||||
|
||||
@Override
|
||||
public SubscriberType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(SubscriberType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getNumberOfLines() {
|
||||
return numberOfLines;
|
||||
}
|
||||
|
||||
public void setNumberOfLines(int numberOfLines) {
|
||||
this.numberOfLines = numberOfLines;
|
||||
}
|
||||
|
||||
public int getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void setCurrent(int current) {
|
||||
this.current = current;
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package de.wwwu.awolf.model.communication;
|
||||
|
||||
public enum SubscriberType {
|
||||
|
||||
EVAL_D,
|
||||
EVALUATION_TABLE_DATA,
|
||||
EVAL_T,
|
||||
LINES_RES,
|
||||
LINES_RES_MULT,
|
||||
ALGORITHM,
|
||||
PICTURE,
|
||||
GENERATOR
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package de.wwwu.awolf.model.communication;
|
||||
|
||||
public class TypeData implements Data {
|
||||
|
||||
private SubscriberType type;
|
||||
|
||||
@Override
|
||||
public SubscriberType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(SubscriberType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package de.wwwu.awolf.model.evaluation;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ComparisonResult {
|
||||
|
||||
private final Map<Algorithm.Type, Line> resultMapping;
|
||||
|
||||
public ComparisonResult() {
|
||||
this.resultMapping = new EnumMap<>(Algorithm.Type.class);
|
||||
}
|
||||
|
||||
public void put(final Algorithm.Type type, final Line lineResult) {
|
||||
this.resultMapping.put(type, lineResult);
|
||||
}
|
||||
|
||||
public Line get(final Algorithm.Type type) {
|
||||
return this.resultMapping.get(type);
|
||||
}
|
||||
|
||||
}
|
168
src/main/java/de/wwwu/awolf/presenter/AbstractPresenter.java
Normal file
@ -0,0 +1,168 @@
|
||||
package de.wwwu.awolf.presenter;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.model.LineModel;
|
||||
import de.wwwu.awolf.model.communication.Data;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.algorithms.AlgorithmHandler;
|
||||
import de.wwwu.awolf.presenter.data.DataHandler;
|
||||
import de.wwwu.awolf.presenter.evaluation.EvaluatationHandler;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import de.wwwu.awolf.view.ViewController;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Flow;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 10.09.2017.
|
||||
*/
|
||||
public abstract class AbstractPresenter implements Flow.Subscriber<Data> {
|
||||
|
||||
private final ExecutorService executor;
|
||||
private LineModel model;
|
||||
private ViewController view;
|
||||
private EvaluatationHandler evaluatationHandler;
|
||||
private DataHandler dataHandler;
|
||||
private AlgorithmHandler algorithmHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*/
|
||||
public AbstractPresenter() {
|
||||
Logging.logDebug("Create instance of Presenter.");
|
||||
this.executor = Executors.newCachedThreadPool();
|
||||
this.dataHandler = new DataHandler(this);
|
||||
this.algorithmHandler = AlgorithmHandler.getInstance();
|
||||
//empty model
|
||||
this.model = new LineModel();
|
||||
//init values null
|
||||
this.view = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Flow.Subscription subscription) {
|
||||
Logging.logInfo("New Subscription: " + subscription.toString());
|
||||
subscription.request(15);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onNext(Data data) {
|
||||
Logging.logDebug("Presenter received message. Type: " + data.getType());
|
||||
switch (data.getType()) {
|
||||
case EVALUATION_TABLE_DATA:
|
||||
evaluatedDatas(data);
|
||||
break;
|
||||
case ALGORITHM:
|
||||
visualizeAlgorithm(data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void visualizeAlgorithm(Data data);
|
||||
|
||||
protected abstract void evaluatedDatas(Data data);
|
||||
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an algorithm specified by a type
|
||||
*
|
||||
* @param type algorithm type
|
||||
* @param lines set of lines
|
||||
*/
|
||||
public void executeAlgorithmByType(Algorithm.Type type, Set<Line> lines) {
|
||||
this.algorithmHandler.runAlgorithmByType(type, lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an algorithm specified by a type
|
||||
*
|
||||
* @param type algorithm type
|
||||
* @param lines set of lines
|
||||
*/
|
||||
public void executeAlgorithmByType(Algorithm.Type type, Set<Line> lines,
|
||||
BooleanProperty guiFlag) {
|
||||
this.algorithmHandler.runAlgorithmByType(type, lines, guiFlag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an algorithm specified by a type (use the Lines from the LineModel)
|
||||
*
|
||||
* @param type algorithm type
|
||||
*/
|
||||
public Line executeAlgorithmByType(Algorithm.Type type, BooleanProperty guiFlag) {
|
||||
if (getModel().getSize() == 0) {
|
||||
Logging.logDebug("No lines in the Model. Nothing to calculate.");
|
||||
throw new IllegalArgumentException();
|
||||
} else {
|
||||
Logging.logDebug("AlgorithmHandler will start " + type.getLabel() + ", with " + getModel().getSize());
|
||||
return this.algorithmHandler.runAlgorithmByType(type, getModel().getLines(), guiFlag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return das zu grunde legende Modell
|
||||
*/
|
||||
public LineModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return die zu grunde legende View
|
||||
*/
|
||||
public ViewController getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param view die zu grunde legende View
|
||||
*/
|
||||
public void registerView(ViewController view) {
|
||||
this.view = view;
|
||||
Logging.logDebug("View has been set.");
|
||||
|
||||
//customize gui
|
||||
Platform.runLater(() -> this.view.initGui());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Evaluation
|
||||
*/
|
||||
EvaluatationHandler getEvaluatationHandler() {
|
||||
return evaluatationHandler;
|
||||
}
|
||||
|
||||
DataHandler getDataHandler() {
|
||||
return dataHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instance of the ExecutorService
|
||||
*
|
||||
* @return ExecutorService instance
|
||||
*/
|
||||
public ExecutorService getExecutor() {
|
||||
return Objects.requireNonNullElseGet(executor, Executors::newCachedThreadPool);
|
||||
}
|
||||
}
|
134
src/main/java/de/wwwu/awolf/presenter/Presenter.java
Normal file
@ -0,0 +1,134 @@
|
||||
package de.wwwu.awolf.presenter;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.model.communication.AlgorithmData;
|
||||
import de.wwwu.awolf.model.communication.Data;
|
||||
import de.wwwu.awolf.model.communication.EvaluationData;
|
||||
import de.wwwu.awolf.presenter.data.DataHandler;
|
||||
import de.wwwu.awolf.presenter.evaluation.EvaluatationHandler;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
import javafx.application.Platform;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 28.05.2017.
|
||||
*/
|
||||
public class Presenter extends AbstractPresenter {
|
||||
|
||||
private static Presenter instance;
|
||||
|
||||
private Presenter() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static Presenter getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Presenter();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visualizeAlgorithm(Data data) {
|
||||
AlgorithmData algorithmData = (AlgorithmData) data;
|
||||
|
||||
Platform.runLater(() -> getView().getAlgorithmTabControllers().get(algorithmData.getAlgorithmType()).updatePlot(getModel(), algorithmData.getLineData())
|
||||
);
|
||||
Logging.logInfo("Type: " + algorithmData.getType() + ". Result: " + algorithmData.getLineData().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void evaluatedDatas(Data data) {
|
||||
EvaluationData evaluationData = (EvaluationData) data;
|
||||
SwingUtilities
|
||||
.invokeLater(
|
||||
() -> getView().appendEvalResults(evaluationData.getMultipleColumnResult()));
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************
|
||||
* Hilfsmethoden
|
||||
***************************************************************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* Startet den Export des akteullen Datensatzes (nur der Geraden)
|
||||
*
|
||||
* @param file Datei in der die Informationen gespeichert werden sollen
|
||||
*/
|
||||
public void exportDataset(File file) {
|
||||
getDataHandler().exportData(file, getModel().getLines());
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet den Export des akteullen Datensatzes im Rahmen der Evaluation (nur der Geraden)
|
||||
*
|
||||
* @param file Datei in der die Informationen gespeichert werden sollen
|
||||
*/
|
||||
public void exportEvaluationDataset(File file) {
|
||||
getDataHandler().exportData(file, getEvaluatationHandler().getData());
|
||||
Logging.logInfo("Export was successful");
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet den Import des Datensatzes.
|
||||
*
|
||||
* @param file importierender Datensatz
|
||||
*/
|
||||
public Set<Line> importDataset(File file) {
|
||||
Set<Line> data = getDataHandler().getData(file);
|
||||
getModel().setLines(data);
|
||||
//Berechnung der Schnittpunkte und vis. der Ergebnisse (anz. Geraden, anz. Schnittpunkte)
|
||||
Logging.logInfo("Import was successful! ");
|
||||
Platform.runLater(() -> getView().getAlgorithmTabControllers().values().forEach(e -> e.updatePlot(getModel(), null))
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet das generieren der Datensätze der Größe <code>n</code>
|
||||
*
|
||||
* @param n Größe des Datensatzes
|
||||
* @param type Art der Datensatzes
|
||||
*/
|
||||
public Set<Line> generateDataset(int n, DataHandler.DataType type) {
|
||||
Set<Line> data = getDataHandler().getData(type, n);
|
||||
getModel().setLines(data);
|
||||
Logging.logInfo("Generate was successful!");
|
||||
Platform.runLater(() -> getView().getAlgorithmTabControllers().values().forEach(e -> e.updatePlot(getModel(), null))
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet die Evaluation zu einen gegegbenen Typ mit den Informationen zu den Datensatz. Beispielsweise kann ein Alg. auf mit verschiedenen Datensätzen untersucht werden, oder mehrere Algorithmen
|
||||
* auf einem gegebenen Datensatz.
|
||||
*
|
||||
* @param typ Typ der Evaluation
|
||||
* @param n Größe des Datensatzes
|
||||
* @param alg code für die auszuführenden Algorithmen (siehe <code>EvaluationPanel.checkSelection()</code> Method)
|
||||
* @param datasetTyp Typ des Datensatzes (Geradem Punktwolke, Kreis und Gerade)
|
||||
*/
|
||||
public void startEvaluation(int typ, int n, int alg, DataHandler.DataType datasetTyp) {
|
||||
getExecutor().submit(new EvaluatationHandler(typ, n, alg, datasetTyp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet die Evaluation zu einen gegegbenen Datensatz, der importiert wird. Beispielsweise kann ein Alg. auf mit verschiedenen Datensätzen untersucht werden, oder mehrere Algorithmen auf einem
|
||||
* gegebenen Datensatz.
|
||||
*
|
||||
* @param typ Typ der Evaluation
|
||||
* @param alg code für die auszuführenden Algorithmen (siehe <code>EvaluationPanel.checkSelection()</code> Method)
|
||||
* @param file Typ des Datensatzes (Geradem Punktwolke, Kreis und Gerade)
|
||||
*/
|
||||
public void startEvaluation(int typ, int alg, File file) {
|
||||
getExecutor().submit(new EvaluatationHandler(typ, alg, file));
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package de.wwwu.awolf.presenter.algorithms;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.model.communication.Data;
|
||||
import de.wwwu.awolf.presenter.AbstractPresenter;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Flow;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 28.05.2017.
|
||||
*/
|
||||
public interface Algorithm extends Callable<Line>, Flow.Publisher<Data> {
|
||||
|
||||
/**
|
||||
* Startet die Berechnung des jeweiligen Algorithmus.
|
||||
*/
|
||||
@Override
|
||||
Line call();
|
||||
|
||||
void setInput(final Set<Line> lines);
|
||||
|
||||
Algorithm.Type getType();
|
||||
|
||||
void setPresenter(AbstractPresenter presenter);
|
||||
|
||||
enum Type {
|
||||
LMS("Least Median of Squares"),
|
||||
RM("Repeated Median"),
|
||||
TS("Theil-Sen"),
|
||||
NAIVE_LMS("Brute Force (LMS)"),
|
||||
NAIVE_RM("Brute Force (RM)"),
|
||||
NAIVE_TS("Brute Force (TS)");
|
||||
|
||||
public final String label;
|
||||
|
||||
Type(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package de.wwwu.awolf.presenter.algorithms;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.Presenter;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AlgorithmHandler {
|
||||
|
||||
private static AlgorithmHandler instance;
|
||||
private Map<Algorithm.Type, Algorithm> algorithmMapping;
|
||||
|
||||
|
||||
private AlgorithmHandler() {
|
||||
//lookup
|
||||
lookUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton getter
|
||||
*
|
||||
* @return instance of the singleton
|
||||
*/
|
||||
public static AlgorithmHandler getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AlgorithmHandler();
|
||||
// Default Constructor
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Line runAlgorithmByType(final Algorithm.Type type, final Set<Line> setOfLines,
|
||||
final BooleanProperty guiFlag) {
|
||||
|
||||
if (guiFlag != null) {
|
||||
guiFlag.setValue(true);
|
||||
}
|
||||
|
||||
//get the instance
|
||||
Algorithm algorithm = algorithmMapping.get(type);
|
||||
algorithm.setPresenter(Presenter.getInstance());
|
||||
algorithm.setInput(setOfLines);
|
||||
Logging.logDebug("run Algorithm: " + algorithm.getClass().getSimpleName());
|
||||
|
||||
//get the executor
|
||||
ExecutorService executor = Presenter.getInstance().getExecutor();
|
||||
ExecutorCompletionService<Line> completionService = new ExecutorCompletionService<>(
|
||||
executor);
|
||||
|
||||
completionService.submit(algorithm);
|
||||
try {
|
||||
|
||||
return completionService.take().get();
|
||||
} catch (InterruptedException e) {
|
||||
Logging.logError(
|
||||
"Interrupt Exception while waiting for result of Algorithm: " + algorithm
|
||||
.getType(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (ExecutionException e) {
|
||||
Logging.logError(
|
||||
"Execution Exception while computing the result of Algorithm: " + algorithm
|
||||
.getType(), e);
|
||||
} finally {
|
||||
if (guiFlag != null) {
|
||||
guiFlag.setValue(false);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Line runAlgorithmByType(final Algorithm.Type type, final Set<Line> setOfLines) {
|
||||
return runAlgorithmByType(type, setOfLines, null);
|
||||
}
|
||||
|
||||
private void lookUp() {
|
||||
Logging.logDebug("Lookup for Algorithm Classes.");
|
||||
ServiceLoader<Algorithm> load = ServiceLoader.load(Algorithm.class);
|
||||
load.reload();
|
||||
algorithmMapping = new EnumMap<>(Algorithm.Type.class);
|
||||
load.forEach(algorithm -> {
|
||||
algorithmMapping.put(algorithm.getType(), algorithm);
|
||||
Logging.logDebug("Found: " + algorithm.getClass().getSimpleName());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,467 @@
|
||||
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.AbstractPresenter;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
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: 28.05.2017.
|
||||
*/
|
||||
public class LeastMedianOfSquaresEstimator implements Algorithm {
|
||||
|
||||
private static final Algorithm.Type type = Type.LMS;
|
||||
|
||||
private List<Line> setOfLines;
|
||||
private int n;
|
||||
private double quantileError;
|
||||
private int kPlus;
|
||||
private int kMinus;
|
||||
private Queue<Interval> intervals;
|
||||
private Interval subSlabU1;
|
||||
private Interval subSlabU2;
|
||||
private Line sigmaMin;
|
||||
private double heightsigmaMin;
|
||||
private double intersectionsPoint;
|
||||
private double constant = 0.5;
|
||||
|
||||
private double slope;
|
||||
private double yInterception;
|
||||
private Flow.Subscriber<? super AlgorithmData> subscriber;
|
||||
|
||||
/**
|
||||
* Algorithmus zum berechnen des LMS-Schätzers
|
||||
* <p>
|
||||
* Paper: Mount, David M, Nathan S Netanyahu, Kathleen Romanik, Ruth Silverman und Angela Y Wu „A practical approximation algorithm for the LMS line estimator“. 2007 Computational statistics &
|
||||
* data Analysis 51.5, S. 2461–2486
|
||||
*/
|
||||
@Override
|
||||
public Line call() {
|
||||
this.n = setOfLines.size();
|
||||
double qPlus = 0.5;
|
||||
quantileError = 0.1;
|
||||
double qMinus = qPlus * (1 - quantileError);
|
||||
kMinus = (int) Math.ceil(n * qMinus);
|
||||
kPlus = (int) Math.ceil(n * qPlus);
|
||||
|
||||
Logging.logInfo("=== S T A R T - L M S ===");
|
||||
long start;
|
||||
long end;
|
||||
start = System.currentTimeMillis();
|
||||
|
||||
//(2.) Let U <- (-inf, inf) be the initial active intervals...
|
||||
Comparator<Interval> comparator = (o1, o2) -> {
|
||||
if (o1.getDistance() < o2.getDistance()) {
|
||||
return -1;
|
||||
}
|
||||
if (o1.getDistance() > o2.getDistance()) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
intervals = new PriorityQueue<>(comparator);
|
||||
intervals.add(new Interval(-10000, 10000));
|
||||
heightsigmaMin = Double.MAX_VALUE;
|
||||
|
||||
//(3.) Apply the following steps as long as the exists active intervals
|
||||
Interval interval;
|
||||
while (!this.intervals.isEmpty()) {
|
||||
interval = this.intervals.peek();
|
||||
if (interval.getActivity()) {
|
||||
//(a.) Select any active Interval and calc. the inversions
|
||||
int numberOfIntersections = countInversions(interval);
|
||||
|
||||
//(b.) apply plane sweep
|
||||
if ((constant * n) >= numberOfIntersections) {
|
||||
sigmaMin = pseudoSweep(interval);
|
||||
} else {
|
||||
//(c.) otherwise....
|
||||
// get random intersections point...
|
||||
Collection<Point> tmpIntersections = IntersectionComputer
|
||||
.getInstance()
|
||||
.compute(setOfLines, interval.getLower(), interval.getUpper());
|
||||
boolean found = false;
|
||||
for (Point tmpIntersection : tmpIntersections) {
|
||||
if (tmpIntersection.getX() > interval.getLower()
|
||||
&& tmpIntersection.getX() < interval.getUpper()) {
|
||||
intersectionsPoint = tmpIntersection.getX();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
splitActiveSlab(intersectionsPoint, interval);
|
||||
//(d.) this may update sigma min
|
||||
upperBound(intersectionsPoint);
|
||||
//(e.) for i={1,2}, call lower bound(Ui)
|
||||
lowerBound(subSlabU1);
|
||||
lowerBound(subSlabU2);
|
||||
|
||||
if (subSlabU1.getActivity()) {
|
||||
this.intervals.add(subSlabU1);
|
||||
}
|
||||
if (subSlabU2.getActivity()) {
|
||||
this.intervals.add(subSlabU2);
|
||||
}
|
||||
|
||||
} else {
|
||||
this.intervals.poll();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.intervals.remove(interval);
|
||||
}
|
||||
}
|
||||
end = System.currentTimeMillis();
|
||||
Logging.logInfo("=== E N D - L M S === " + ((end - start) / 1000));
|
||||
|
||||
return pepareResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Set<Line> lines) {
|
||||
this.setOfLines = new LinkedList<>(lines);
|
||||
setN(this.setOfLines.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPresenter(AbstractPresenter presenter) {
|
||||
subscribe(presenter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Liefert die Anzahl der Schnittpunkte in einem Intervall
|
||||
*
|
||||
* @param interval Intervall
|
||||
* @return Anzahl der Schnittpunkte
|
||||
*/
|
||||
public int countInversions(Interval interval) {
|
||||
return IntersectionComputer.getInstance()
|
||||
.compute(setOfLines, interval.getLower(), interval.getUpper()).size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* In der Literatur wird ein planesweep vorrausgesetzt um in einem Intervall das minimale kMinus Segment zu identifizieren. An dieser Stelle wird eine naivere Lösung verwendet, mithilfe der
|
||||
* Schleife werden alle Schnittpunkte betrachtet und bei passenden x-Koordinaten werden wird die vertikale Gerade auf kMinus Segmente untersucht.
|
||||
*
|
||||
* @param interval
|
||||
* @return
|
||||
*/
|
||||
public Line pseudoSweep(Interval interval) {
|
||||
|
||||
//initialisiere die x-Queue mit den 2D Punkten und sortiere nach x-Lexikographischer Ordnung
|
||||
List<Point> xQueue = new ArrayList<>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
Collections.sort(xQueue);
|
||||
|
||||
Line bracelet = sigmaMin;
|
||||
double heightOfBracelet = heightsigmaMin;
|
||||
|
||||
for (Point current : xQueue) {
|
||||
Double[] currentBracelet = calcKMinusBracelet(current, kMinus);
|
||||
|
||||
if (currentBracelet == null) {
|
||||
continue;
|
||||
} else if (currentBracelet[0] < heightOfBracelet) {
|
||||
heightOfBracelet = currentBracelet[0];
|
||||
bracelet = new Line(current.getX(), current.getX(), currentBracelet[1],
|
||||
currentBracelet[2]);
|
||||
}
|
||||
}
|
||||
|
||||
interval.setActivity(false);
|
||||
return bracelet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode spaltet den aktiven Interval an der x Koordinate point. Es werden zwei neue Slabs erzeugt.
|
||||
*
|
||||
* @param point x Koordinate an der, der Split geschieht.
|
||||
*/
|
||||
public void splitActiveSlab(double point, Interval active) {
|
||||
subSlabU1 = new Interval(active.getLower() + 0.01, point);
|
||||
subSlabU2 = new Interval(point, active.getUpper());
|
||||
|
||||
this.intervals.remove(active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zu einer vertikalen Gerade werden kMinus Segmente erzeugt und geprüft ob eine bessere Lösung als SigmaMin vorliegt.
|
||||
*
|
||||
* @param point x-Koordinate zur Konstruktion der vertikalen Gerade
|
||||
*/
|
||||
public void upperBound(double point) {
|
||||
|
||||
double height = heightsigmaMin;
|
||||
double tmpHeight;
|
||||
List<Double> sortedLineSequence = getEjValues(point);
|
||||
|
||||
int itnbr = ((n - kMinus) + 1);
|
||||
for (int i = 0; i < itnbr; i++) {
|
||||
tmpHeight = sortedLineSequence.get((i + kMinus) - 1) - sortedLineSequence.get(i);
|
||||
if (tmpHeight < height) {
|
||||
height = tmpHeight;
|
||||
}
|
||||
|
||||
if (height < heightsigmaMin) {
|
||||
heightsigmaMin = height;
|
||||
if (sigmaMin != null) {
|
||||
sigmaMin.setEndPoints(point, sortedLineSequence.get(i)
|
||||
, point, sortedLineSequence.get((i + kMinus) - 1));
|
||||
} else {
|
||||
sigmaMin = new Line(point, point, sortedLineSequence.get(i),
|
||||
sortedLineSequence.get((i + kMinus) - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Methode prüft ob das übergebene Intervall die untere Schranke einer potenziellen Lösung erfüllt.
|
||||
*
|
||||
* @param pslab übergebene Intervall
|
||||
*/
|
||||
public void lowerBound(Interval pslab) {
|
||||
|
||||
int[] alpha = new int[n];
|
||||
int[] beta = new int[n];
|
||||
int strictlyGreater = 0;
|
||||
|
||||
//Teil I.
|
||||
List<Double> umaxList;
|
||||
List<Double> uminList;
|
||||
|
||||
//y koordinaten der Schnittpunkte
|
||||
List<Line> lines = new ArrayList<>();
|
||||
for (Line p : setOfLines) {
|
||||
lines.add(
|
||||
new Line(pslab.getLower(), pslab.getUpper(),
|
||||
((pslab.getLower() * p.getM()) + p.getB()),
|
||||
((pslab.getUpper() * p.getM()) + p.getB())));
|
||||
}
|
||||
|
||||
umaxList = getEjValues(pslab.getUpper());
|
||||
uminList = getEjValues(pslab.getLower());
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
Line level = new Line(pslab.getLower(), pslab.getUpper(), uminList.get(i),
|
||||
umaxList.get(i));
|
||||
for (Line line : lines) {
|
||||
if ((line.getY1() < level.getY1()) && (line.getY2() < level.getY2())) {
|
||||
alpha[i]++;
|
||||
}
|
||||
|
||||
if ((line.getY1() > level.getY1()) && (line.getY2() > level.getY2())) {
|
||||
strictlyGreater++;
|
||||
}
|
||||
}
|
||||
beta[i] = n - (alpha[i] + strictlyGreater);
|
||||
strictlyGreater = 0;
|
||||
}
|
||||
|
||||
//Teil II.
|
||||
int i = 0;
|
||||
double h;
|
||||
pslab.setActivity(false);
|
||||
for (int j = 0; j < n; j++) {
|
||||
while ((i < n && (Math.abs(beta[i] - alpha[j]) < kPlus))) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i >= n) {
|
||||
pslab.setActivity(false);
|
||||
break;
|
||||
} else {
|
||||
h = Math.min(Math.abs(uminList.get(j) - uminList.get(i)),
|
||||
Math.abs(umaxList.get(j) - umaxList.get(i)));
|
||||
double error = 0.01;
|
||||
if (((1 + error) * h) < heightsigmaMin) {
|
||||
pslab.setActivity(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Schnittpunkte der Geraden und der vertikalen Gerade u. Im paper sind diese Werte als e_j Werte bekannt.
|
||||
*
|
||||
* @param u vertikale Gerade
|
||||
* @return Liste der Schnittpunkte (da u bekannt werden nur die y Werte zurück gegeben)
|
||||
*/
|
||||
public List<Double> getEjValues(double u) {
|
||||
|
||||
List<Double> ret = new ArrayList<>();
|
||||
|
||||
for (Line p : setOfLines) {
|
||||
ret.add((p.getM() * u) + p.getB());
|
||||
}
|
||||
|
||||
Collections.sort(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Die Funktion berechnet anhand einer vertikalen Gerade x = px das sogenannte kleinste kMinus Bracelet. Mit anderen Worten es wird eine vertikale Teilgerade berechnet die mindestens kMinus
|
||||
* Geraden schneidet und dabei minimal ist.
|
||||
*
|
||||
* @param px Koordinate um die "vertikale Gerade" zu simulieren.
|
||||
* @return Das Array enthält höhe des Bracelet, e_j und e_(j + kMinus - 1)
|
||||
*/
|
||||
public Double[] calcKMinusBracelet(Point px, int kMinusValue) {
|
||||
|
||||
//y Koordinaten für das kMinus brecalet
|
||||
List<Double> intersections = new LinkedList<>();
|
||||
for (Line line : setOfLines) {
|
||||
intersections.add((px.getX() * line.getM()) + line.getB());
|
||||
}
|
||||
if (intersections.size() >= kMinusValue) {
|
||||
Collections.sort(intersections);
|
||||
double height = Math
|
||||
.abs(intersections.get(0) - intersections.get(kMinusValue - 1));
|
||||
return new Double[]{height, intersections.get(0),
|
||||
intersections.get(kMinusValue - 1)};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Line pepareResult() {
|
||||
if (this.subscriber != null) {
|
||||
double m = ((getSigmaMin().getX2() + getSigmaMin().getX1()) * 0.5);
|
||||
double b = (getSigmaMin().getY2() + getSigmaMin().getY1()) * -0.5;
|
||||
|
||||
slope = m;
|
||||
yInterception = b;
|
||||
|
||||
AlgorithmData data = new AlgorithmData();
|
||||
data.setAlgorithmType(getType());
|
||||
data.setType(SubscriberType.ALGORITHM);
|
||||
data.setLineData(new Line(m, b));
|
||||
this.subscriber.onNext(data);
|
||||
} else {
|
||||
double m = (getSigmaMin().getX2() + getSigmaMin().getX1()) * 0.5;
|
||||
double b = (getSigmaMin().getY2() + getSigmaMin().getY1()) * -0.5;
|
||||
|
||||
slope = m;
|
||||
yInterception = b;
|
||||
}
|
||||
|
||||
return new Line(getSlope(), getYInterception());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Anzahl der Geraden
|
||||
*/
|
||||
public int getN() {
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n Anzahl der Geraden
|
||||
*/
|
||||
public void setN(int n) {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param quantileError Parameter quantile Fehler
|
||||
*/
|
||||
public void setQuantileError(double quantileError) {
|
||||
this.quantileError = quantileError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kMinus kMinus index
|
||||
*/
|
||||
public void setkMinus(int kMinus) {
|
||||
this.kMinus = kMinus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return duale Streifen Sigma_min
|
||||
*/
|
||||
public Line getSigmaMin() {
|
||||
return sigmaMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sigmaMin duale Streifen Sigma_min
|
||||
*/
|
||||
public void setSigmaMin(Line sigmaMin) {
|
||||
this.sigmaMin = sigmaMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param heightsigmaMin höhe von Sigma_min
|
||||
*/
|
||||
public void setHeightsigmaMin(double heightsigmaMin) {
|
||||
this.heightsigmaMin = heightsigmaMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param constant Parameter Konstante
|
||||
*/
|
||||
public void setConstant(Double constant) {
|
||||
this.constant = constant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Steigung
|
||||
*/
|
||||
public Double getSlope() {
|
||||
return slope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Achsenabschnitt
|
||||
*/
|
||||
public Double getYInterception() {
|
||||
return yInterception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,356 @@
|
||||
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.AbstractPresenter;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.util.FastElementSelector;
|
||||
import de.wwwu.awolf.presenter.util.IntersectionComputer;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import de.wwwu.awolf.presenter.util.RandomSampler;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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: 28.05.2017.
|
||||
*/
|
||||
public class RepeatedMedianEstimator implements Algorithm {
|
||||
|
||||
|
||||
private static final Algorithm.Type type = Type.RM;
|
||||
|
||||
private AbstractPresenter presenter;
|
||||
private List<Line> setOfLines;
|
||||
private Interval interval;
|
||||
private Interval original;
|
||||
|
||||
//in der Literatur als L_i, C_i, und R_i bekannt
|
||||
private int countLeftSlab;
|
||||
private int countCenterSlab;
|
||||
private int countRightSlab;
|
||||
|
||||
//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;
|
||||
private double k;
|
||||
private double kLow;
|
||||
private double kHigh;
|
||||
private double beta;
|
||||
|
||||
private double slope;
|
||||
private double yInterception;
|
||||
private Flow.Subscriber<? super AlgorithmData> subscriber;
|
||||
|
||||
|
||||
/**
|
||||
* Führt den Algortihmus zur Berechnung des RM-Schätzers durch.
|
||||
* <p>
|
||||
* Paper: Matousek, Jiri, D. M. Mount und N. S. Netanyahu „Efficient Randomized Algorithms for the Repeated Median Line Estimator“. 1998 Algorithmica 20.2, S. 136–150
|
||||
*/
|
||||
public Line call() {
|
||||
|
||||
n = setOfLines.size();
|
||||
interval = new Interval(-10000, 10000);
|
||||
original = new Interval(-10000, 10000);
|
||||
beta = 0.5;
|
||||
|
||||
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 = 0;
|
||||
countRightSlab = 0;
|
||||
countCenterSlab = setOfLines.size();
|
||||
}
|
||||
|
||||
Logging.logInfo("=== S T A R T - R M ===");
|
||||
long start;
|
||||
long end;
|
||||
start = System.currentTimeMillis();
|
||||
double thetaLow = 0;
|
||||
double thetaHigh = 0;
|
||||
|
||||
while (countCenterSlab > 1) {
|
||||
n = countCenterSlab;
|
||||
r = Math.ceil(Math.pow(n, beta));
|
||||
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<>();
|
||||
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(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(thetaLow, thetaHigh);
|
||||
|
||||
//verkleinere das Intervall
|
||||
contractIntervals(thetaLow, thetaHigh);
|
||||
|
||||
}
|
||||
|
||||
end = System.currentTimeMillis();
|
||||
Logging.logInfo("=== E N D - R M === " + ((end - start) / 1000));
|
||||
|
||||
return pepareResult(thetaLow, thetaHigh);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Set<Line> lines) {
|
||||
this.setOfLines = new LinkedList<>(lines);
|
||||
this.n = setOfLines.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPresenter(AbstractPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
subscribe(presenter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Berechnet die mediane x-Koordinate über den Schnittpunkten.
|
||||
*
|
||||
* @param sampledLine Stichprobe von Geraden
|
||||
* @return mediane x-Koordinate über den Schnittpunkten
|
||||
*/
|
||||
public Double estimateMedianIntersectionAbscissas(List<Line> lines, Line sampledLine) {
|
||||
|
||||
List<Double> intersections = IntersectionComputer.getInstance()
|
||||
.calculateIntersectionAbscissas(lines, sampledLine, original.getLower(),
|
||||
original.getUpper());
|
||||
List<Double> left = IntersectionComputer.getInstance()
|
||||
.calculateIntersectionAbscissas(lines, sampledLine, original.getLower(),
|
||||
interval.getLower());
|
||||
List<Double> center = IntersectionComputer.getInstance()
|
||||
.calculateIntersectionAbscissas(lines, sampledLine, interval.getLower(),
|
||||
interval.getUpper());
|
||||
|
||||
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() && !intersections.isEmpty()) {
|
||||
accessIndex = intersections.size() - 1;
|
||||
} else {
|
||||
accessIndex = (int) i;
|
||||
}
|
||||
|
||||
return FastElementSelector.randomizedSelect(intersections, accessIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die potenziell neuen Intervallgrenzen.
|
||||
*/
|
||||
public void computeSlabBorders() {
|
||||
kLow = Math.max(1, Math.floor(((r * k) / (countCenterSlab))
|
||||
- ((3 * Math.sqrt(r)) * (0.5))));
|
||||
kHigh = Math.min(r, Math.floor(((r * k) / (countCenterSlab))
|
||||
+ ((3 * Math.sqrt(r)) * (0.5))));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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(final double lower, final double upper) {
|
||||
IntersectionComputer instance = IntersectionComputer.getInstance();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final double lower, final double upper) {
|
||||
double max = Math.max(countLeftSlab, Math.max(countCenterSlab, countRightSlab));
|
||||
|
||||
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 (newIntervalIsC) {
|
||||
interval.setLower(lower);
|
||||
interval.setUpper(upper);
|
||||
} else if (newIntervalIsL) {
|
||||
interval.setUpper(lower);
|
||||
} else if (newIntervalIsR) {
|
||||
interval.setLower(upper);
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
});
|
||||
|
||||
yInterception = FastElementSelector.randomizedSelect(potentialYInterceptions,
|
||||
Math.floor(potentialYInterceptions.size() * 0.5));
|
||||
|
||||
if (this.subscriber != null) {
|
||||
AlgorithmData data = new AlgorithmData();
|
||||
data.setAlgorithmType(getType());
|
||||
data.setType(SubscriberType.ALGORITHM);
|
||||
data.setLineData(new Line(getSlope(), getyInterception()));
|
||||
this.subscriber.onNext(data);
|
||||
}
|
||||
|
||||
return new Line(getSlope(), getyInterception());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Anzahl der Geraden
|
||||
*/
|
||||
public Integer getN() {
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n Anzahl der Geraden
|
||||
*/
|
||||
public void setN(Integer n) {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param beta Parameter Beta
|
||||
*/
|
||||
public void setBeta(Double beta) {
|
||||
this.beta = beta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Steigung
|
||||
*/
|
||||
public Double getSlope() {
|
||||
return slope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Achsenabschnitt
|
||||
*/
|
||||
public Double getyInterception() {
|
||||
return yInterception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return temporäres untere Intervallgrenze
|
||||
*/
|
||||
public Double getkLow() {
|
||||
return kLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kLow temporäres untere Intervallgrenze
|
||||
*/
|
||||
public void setkLow(Double kLow) {
|
||||
this.kLow = kLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return temporäres oberes Intervallgrenze
|
||||
*/
|
||||
public Double getkHigh() {
|
||||
return kHigh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kHigh temporäres oberes Intervallgrenze
|
||||
*/
|
||||
public void setkHigh(Double kHigh) {
|
||||
this.kHigh = kHigh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return verteilung der Punkte
|
||||
*/
|
||||
public int getCountLeftSlab() {
|
||||
return countLeftSlab;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return verteilung der Punkte
|
||||
*/
|
||||
public int getCountCenterSlab() {
|
||||
return countCenterSlab;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return verteilung der Punkte
|
||||
*/
|
||||
public int getCountRightSlab() {
|
||||
return countRightSlab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,248 @@
|
||||
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.AbstractPresenter;
|
||||
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.IntersectionComputer;
|
||||
import de.wwwu.awolf.presenter.util.RandomSampler;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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: 28.05.2017.
|
||||
*/
|
||||
public class TheilSenEstimator implements Algorithm {
|
||||
|
||||
|
||||
private static final Algorithm.Type type = Type.TS;
|
||||
|
||||
private final double POSITIV_INF = 9999.0;
|
||||
private final double NEGATIV_INF = -9999.0;
|
||||
private final double EPSILON = 0.00001;
|
||||
private List<Line> setOfLines;
|
||||
//Hilfsvariablen (siehe original Paper)
|
||||
private double j;
|
||||
private int jA;
|
||||
private int jB;
|
||||
private double r;
|
||||
private int n;
|
||||
private double N;
|
||||
private int k;
|
||||
//Intervall und die temporaeren Grenzen
|
||||
private Interval interval;
|
||||
private double aVariant;
|
||||
private double bVariant;
|
||||
private double slope;
|
||||
private double yInterception;
|
||||
private Flow.Subscriber<? super AlgorithmData> subscriber;
|
||||
private AbstractPresenter presenter;
|
||||
|
||||
|
||||
/**
|
||||
* Randomisierter Algorithmus zur Berechnung des Theil-Sen Schätzers. Algorithmus stammt aus dem Paper: "Jiri Matousek, Randomized optimal algorithm for slope selection, Information Processing
|
||||
* Letters 39 (1991) 183-187
|
||||
*/
|
||||
public Line call() {
|
||||
|
||||
this.n = this.setOfLines.size();
|
||||
this.N = BinomialCoeffizient.run(n, 2);
|
||||
//this.k = Integer.valueOf((int) (N * 0.5)) - 1;
|
||||
this.k = (int) (N / 2);
|
||||
|
||||
interval = new Interval(NEGATIV_INF, POSITIV_INF);
|
||||
//damit eine initiale Ordnung herscht
|
||||
//Collections.sort(intervalIntersections);
|
||||
|
||||
r = n;
|
||||
List<Point> intervalIntersections = new LinkedList<>(IntersectionComputer.getInstance()
|
||||
.compute(setOfLines, interval.getLower(), interval.getUpper()));
|
||||
while (true) {
|
||||
if (this.N <= n
|
||||
|| (Math.abs(interval.getUpper() - interval.getLower())) < EPSILON) {
|
||||
break;
|
||||
} else {
|
||||
//Anzahl der Schnittpunkte im Intervall [-Inf, a)
|
||||
int numberOfIntersections = getIntervalSize(NEGATIV_INF,
|
||||
interval.getLower());
|
||||
|
||||
//Randomized Interpolating Search
|
||||
j = (r / N) * (double) (k - numberOfIntersections);
|
||||
jA = (int) Math.max(1, Math.floor(j - (1.5 * Math.sqrt(r))));
|
||||
jB = (int) Math.min(r, Math.floor(j + (1.5 * Math.sqrt(r))));
|
||||
|
||||
|
||||
/* Suche nach einem passenderen und kleineren Intervall
|
||||
Schleife terminiert wenn die das k-te Elemnet zwischen aVariant und bVariant liegt und
|
||||
das Intrvall weniger als 11*N / sqrt(r) Elemente besitzt */
|
||||
do {
|
||||
//zufällige Stichprobe
|
||||
List<Point> sampledIntersections = RandomSampler
|
||||
.run(intervalIntersections, r);
|
||||
|
||||
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 = getIntervalSize(interval.getLower(), interval.getUpper());
|
||||
}
|
||||
}
|
||||
|
||||
return pepareResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Set<Line> lines) {
|
||||
this.setOfLines = new LinkedList<>(lines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPresenter(AbstractPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
subscribe(presenter);
|
||||
}
|
||||
|
||||
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 Schnittpunkt in diesem Interval enthalten sein. des weiteren soll die Anzahl der Schnittpunkte im
|
||||
* Interval kleiner oder gleich dem Term: (11*N)/sqrt(r) sein.
|
||||
*
|
||||
* @return Boolscher Wert ob die Bedingung erfüllt ist
|
||||
*/
|
||||
private Boolean checkCondition() {
|
||||
//Double kthElement = FastElementSelector.randomizedSelect(xCoordinates, k);
|
||||
//Boolean cond1 = (kthElement > aVariant) && (kthElement <= bVariant);
|
||||
|
||||
int lowerCount = getIntervalSize(NEGATIV_INF, aVariant);
|
||||
int higherCount = getIntervalSize(NEGATIV_INF, bVariant);
|
||||
|
||||
Boolean conda = k > lowerCount;
|
||||
Boolean condb = k <= higherCount;
|
||||
|
||||
Boolean cond1 = conda && condb;
|
||||
|
||||
Boolean cond2 = (higherCount - lowerCount) <= ((11 * N) / Math.sqrt(r));
|
||||
|
||||
return (cond1 && cond2) || (aVariant == bVariant);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Berechne wieviele von den Schnittpunkten in dem Interval zwischen <code>a</code> und
|
||||
* <code>b</code> enthalten sind.
|
||||
*
|
||||
* @param a untere Grenze des Intervals
|
||||
* @param b obere Grenze des Intrvals
|
||||
* @return Anzahl der Schnittpunkte im Interval [a,b)
|
||||
*/
|
||||
public int getIntervalSize(double a, double b) {
|
||||
return getOpenIntervalElements(a, b).size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechne wieviele von den Schnittpunkten in dem Interval zwischen <code>a</code> und
|
||||
* <code>b</code> enthalten sind. Zusätzlich werden diese Schnittpunkte in einer Liste
|
||||
* festgehalten und diese werden zurückgeliefert.
|
||||
*
|
||||
* @param a untere Grenze des Intervals
|
||||
* @param b obere Grenze des Intrvals
|
||||
* @return Liste der Schnittpunkte die im Interval (a,b) vertreten sind
|
||||
*/
|
||||
public List<Point> getOpenIntervalElements(double a, double b) {
|
||||
Collection<Point> intersections = IntersectionComputer.getInstance()
|
||||
.compute(setOfLines, a, b);
|
||||
return new ArrayList<>(intersections);
|
||||
}
|
||||
|
||||
private Line pepareResult() {
|
||||
double m, x;
|
||||
double b, y;
|
||||
|
||||
List<Point> resultSt = getOpenIntervalElements(interval.getLower(),
|
||||
interval.getUpper());
|
||||
List<Double> resultAbscissas = new ArrayList<>();
|
||||
|
||||
for (Point p : resultSt) {
|
||||
resultAbscissas.add(p.getX());
|
||||
}
|
||||
|
||||
List<Double> yCoords = new ArrayList<>();
|
||||
|
||||
for (Point p : getOpenIntervalElements(interval.getLower(), interval.getUpper())) {
|
||||
yCoords.add(p.getY());
|
||||
}
|
||||
|
||||
double pseudoIndex = getIntervalSize(NEGATIV_INF, interval.getLower()) * 1.0;
|
||||
m = FastElementSelector.randomizedSelect(resultAbscissas, k - pseudoIndex);
|
||||
|
||||
Set<Double> unique = new LinkedHashSet<>(yCoords);
|
||||
yCoords.clear();
|
||||
yCoords.addAll(unique);
|
||||
b = FastElementSelector.randomizedSelect(yCoords, yCoords.size() * 0.5) * -1;
|
||||
slope = m;
|
||||
yInterception = b;
|
||||
|
||||
if (this.subscriber != null) {
|
||||
AlgorithmData data = new AlgorithmData();
|
||||
data.setAlgorithmType(getType());
|
||||
data.setType(SubscriberType.ALGORITHM);
|
||||
data.setLineData(new Line(m, b));
|
||||
this.subscriber.onNext(data);
|
||||
}
|
||||
|
||||
return new Line(getSlope(), getYInterception());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Steigung
|
||||
*/
|
||||
public Double getSlope() {
|
||||
return slope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Achsenabschnitt
|
||||
*/
|
||||
public Double getYInterception() {
|
||||
return yInterception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package de.wwwu.awolf.presenter.algorithms.naiv;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
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.AbstractPresenter;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.util.FastElementSelector;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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: 15.09.2017.
|
||||
*/
|
||||
public class NaivLeastMedianOfSquaresEstimator implements Algorithm {
|
||||
|
||||
private static final Algorithm.Type type = Type.NAIVE_LMS;
|
||||
private List<Line> setOfLines = new ArrayList<>();
|
||||
|
||||
private int n;
|
||||
private double ds, b, m;
|
||||
private Flow.Subscriber<? super Data> subscriber;
|
||||
private AbstractPresenter presenter;
|
||||
|
||||
|
||||
/**
|
||||
* Crude Algorithmus zum berechnen des LSM-Schätzers.
|
||||
*/
|
||||
private Line crudeAlg() {
|
||||
ds = Double.MAX_VALUE;
|
||||
b = 0d;
|
||||
m = 0d;
|
||||
List<Line> triple = new ArrayList<>();
|
||||
double beta;
|
||||
double alpha;
|
||||
double dijk;
|
||||
Logging.logInfo("=== S T A R T - naiv L M S ===");
|
||||
long start;
|
||||
long end;
|
||||
start = System.currentTimeMillis();
|
||||
for (Line i : setOfLines) {
|
||||
for (Line j : setOfLines) {
|
||||
for (Line k : setOfLines) {
|
||||
triple.add(i);
|
||||
triple.add(j);
|
||||
triple.add(k);
|
||||
Collections.sort(triple);
|
||||
beta =
|
||||
(triple.get(0).getB() - triple.get(2).getB()) / (
|
||||
triple.get(0).getM() - triple.get(2)
|
||||
.getM());
|
||||
alpha =
|
||||
(triple.get(1).getB() + triple.get(2).getB() - (beta * (
|
||||
triple.get(1).getM() + triple
|
||||
.get(2).getM()))) * 0.5;
|
||||
dijk = f(alpha, beta);
|
||||
if (dijk < ds) {
|
||||
ds = dijk;
|
||||
b = alpha;
|
||||
m = beta;
|
||||
}
|
||||
triple.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
end = System.currentTimeMillis();
|
||||
Logging.logInfo("=== E N D - naiv L M S ===");
|
||||
Logging.logInfo("Slope: " + getSlope() + ", y-Interception: " + getYInterception());
|
||||
|
||||
AlgorithmData data = new AlgorithmData();
|
||||
data.setAlgorithmType(getType());
|
||||
data.setType(SubscriberType.ALGORITHM);
|
||||
data.setLineData(new Line(getSlope(), getYInterception()));
|
||||
this.subscriber.onNext(data);
|
||||
|
||||
return new Line(getSlope(), getYInterception());
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Gerade mit dem medianen Fehler
|
||||
*
|
||||
* @param a y-Achsenabschnitt
|
||||
* @param b Steigung
|
||||
* @return medianer Fehler
|
||||
*/
|
||||
private Double f(double a, double b) {
|
||||
List<Double> res = new ArrayList<>();
|
||||
for (Line p : setOfLines) {
|
||||
res.add(Math.abs(p.getB() - (a + b * p.getM())));
|
||||
}
|
||||
return FastElementSelector.randomizedSelect(res, res.size() * 0.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Line call() {
|
||||
return crudeAlg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Set<Line> lines) {
|
||||
this.setOfLines = new LinkedList<>(lines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPresenter(AbstractPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
subscribe(presenter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Achsenabschnitt
|
||||
*/
|
||||
public Double getYInterception() {
|
||||
return b * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Steigung
|
||||
*/
|
||||
public Double getSlope() {
|
||||
return m * -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
package de.wwwu.awolf.presenter.algorithms.naiv;
|
||||
|
||||
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.AbstractPresenter;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.util.FastElementSelector;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.util.ArrayList;
|
||||
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: 15.09.2017.
|
||||
*/
|
||||
public class NaivRepeatedMedianEstimator implements Algorithm {
|
||||
|
||||
private static final Algorithm.Type type = Type.NAIVE_RM;
|
||||
|
||||
private List<Line> setOfLines;
|
||||
private Map<String, List<Double>> slopesPerLine;
|
||||
private Map<String, List<Double>> interceptPerLine;
|
||||
private List<Double> xMedians;
|
||||
private List<Double> yMedians;
|
||||
private double medianX;
|
||||
private double medianY;
|
||||
private Flow.Subscriber<? super Data> subscriber;
|
||||
private AbstractPresenter presenter;
|
||||
|
||||
@Override
|
||||
public Line call() {
|
||||
|
||||
slopesPerLine = new HashMap<>();
|
||||
interceptPerLine = new HashMap<>();
|
||||
xMedians = new ArrayList<>();
|
||||
yMedians = new ArrayList<>();
|
||||
|
||||
//init the List for the slopes
|
||||
Logging.logInfo("=== S T A R T - naiv R M ===");
|
||||
long start;
|
||||
long end;
|
||||
start = System.currentTimeMillis();
|
||||
for (Line leq : setOfLines) {
|
||||
slopesPerLine.computeIfAbsent(leq.getId(), k -> new ArrayList<>());
|
||||
interceptPerLine.computeIfAbsent(leq.getId(), k -> new ArrayList<>());
|
||||
}
|
||||
|
||||
//calculate all slopes for each line
|
||||
Point ret;
|
||||
for (int i = 0; i < setOfLines.size(); i++) {
|
||||
for (int j = i + 1; j < setOfLines.size(); j++) {
|
||||
ret = calculateLine(setOfLines.get(i), setOfLines.get(j));
|
||||
slopesPerLine.get(setOfLines.get(i).getId()).add(ret.getX());
|
||||
interceptPerLine.get(setOfLines.get(i).getId()).add(ret.getY());
|
||||
}
|
||||
}
|
||||
|
||||
//berechne mediane Steigung
|
||||
for (String l : slopesPerLine.keySet()) {
|
||||
List<Double> list = slopesPerLine.get(l);
|
||||
int size = list.size() / 2;
|
||||
if (size > 0) {
|
||||
double medianX = FastElementSelector.randomizedSelect(list, size);
|
||||
xMedians.add(medianX);
|
||||
}
|
||||
}
|
||||
|
||||
//berechne medianen y-Achsenabschnitt
|
||||
for (String l : interceptPerLine.keySet()) {
|
||||
List<Double> list = interceptPerLine.get(l);
|
||||
int size = list.size() / 2;
|
||||
if (size > 0) {
|
||||
double medianY = FastElementSelector.randomizedSelect(list, size);
|
||||
yMedians.add(medianY);
|
||||
}
|
||||
}
|
||||
|
||||
medianX = FastElementSelector.randomizedSelect(xMedians, xMedians.size() * 0.5);
|
||||
medianY = FastElementSelector.randomizedSelect(yMedians, yMedians.size() * 0.5);
|
||||
end = System.currentTimeMillis();
|
||||
Logging.logInfo("=== E N D - naiv R M ===");
|
||||
Logging.logInfo("Slope: " + getSlope() + ", y-Interception: " + getYInterception());
|
||||
AlgorithmData data = new AlgorithmData();
|
||||
data.setAlgorithmType(getType());
|
||||
data.setType(SubscriberType.ALGORITHM);
|
||||
data.setLineData(new Line(getSlope(), getYInterception()));
|
||||
this.subscriber.onNext(data);
|
||||
return new Line(getSlope(), getYInterception());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Set<Line> lines) {
|
||||
this.setOfLines = new ArrayList<>(lines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPresenter(AbstractPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
subscribe(presenter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Geraden zwischen zwei Punkten im dualen Raum.
|
||||
*
|
||||
* @param startPoint Gerade 1 => Startpunkt mit den Koordianten (m,b)
|
||||
* @param endPoint Gerade 2 => Endpunkt mit den Koordianten (m', b')
|
||||
* @return
|
||||
*/
|
||||
private Point calculateLine(Line startPoint, Line endPoint) {
|
||||
double xi;
|
||||
double xj;
|
||||
double yi;
|
||||
double yj;
|
||||
|
||||
if (endPoint.getM() > startPoint.getM()) {
|
||||
xi = startPoint.getM();
|
||||
yi = startPoint.getB();
|
||||
xj = endPoint.getM();
|
||||
yj = endPoint.getB();
|
||||
} else {
|
||||
xj = startPoint.getM();
|
||||
yj = startPoint.getB();
|
||||
xi = endPoint.getM();
|
||||
yi = endPoint.getB();
|
||||
}
|
||||
|
||||
double m = (yj - yi) / (xj - xi);
|
||||
double b = ((xj * yi) - (xi * yj)) / (xj - xi);
|
||||
return new Point(m, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Steigung
|
||||
*/
|
||||
public double getSlope() {
|
||||
return medianX * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Achsenabschnitt
|
||||
*/
|
||||
public double getYInterception() {
|
||||
return medianY * -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package de.wwwu.awolf.presenter.algorithms.naiv;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
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.AbstractPresenter;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.util.FastElementSelector;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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: 15.09.2017.
|
||||
*/
|
||||
public class NaivTheilSenEstimator implements Algorithm {
|
||||
|
||||
private static final Algorithm.Type type = Type.NAIVE_TS;
|
||||
|
||||
private List<Line> setOfLines;
|
||||
private double slope;
|
||||
private double yInterception;
|
||||
private Flow.Subscriber<? super Data> subscriber;
|
||||
private AbstractPresenter presenter;
|
||||
|
||||
@Override
|
||||
public Line call() {
|
||||
this.slope = 0d;
|
||||
this.yInterception = 0d;
|
||||
Logging.logInfo("=== S T A R T - naiv T S ===");
|
||||
long start;
|
||||
long end;
|
||||
start = System.currentTimeMillis();
|
||||
List<Double> slopesList = new ArrayList<>();
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < setOfLines.size(); i++) {
|
||||
double x = setOfLines.get(i).getM();
|
||||
double y = setOfLines.get(i).getB();
|
||||
|
||||
for (int j = i + 1; j < setOfLines.size(); j++) {
|
||||
if (x != setOfLines.get(j)
|
||||
.getM()) { // x must be different, otherwise slope becomes infinite
|
||||
Double slope =
|
||||
(setOfLines.get(j).getB() - y) / (setOfLines.get(j).getM() - x);
|
||||
slopesList.add(slope);
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Double> list1 = new ArrayList<>();
|
||||
List<Double> list2 = new ArrayList<>();
|
||||
for (Line line : setOfLines) {
|
||||
list1.add(line.getM());
|
||||
list2.add(line.getB());
|
||||
}
|
||||
double median1 = FastElementSelector.randomizedSelect(list1, list1.size() * 0.5);
|
||||
double median2 = FastElementSelector.randomizedSelect(list2, list2.size() * 0.5);
|
||||
slope = FastElementSelector.randomizedSelect(slopesList, slopesList.size() * 0.5);
|
||||
yInterception = median2 - slope * median1;
|
||||
end = System.currentTimeMillis();
|
||||
Logging.logInfo("=== E N D - naiv T S ===");
|
||||
Logging.logInfo("Slope: " + getSlope() + ", y-Interception: " + getYInterception());
|
||||
AlgorithmData data = new AlgorithmData();
|
||||
data.setAlgorithmType(getType());
|
||||
data.setType(SubscriberType.ALGORITHM);
|
||||
data.setLineData(new Line(getSlope(), getYInterception()));
|
||||
this.subscriber.onNext(data);
|
||||
return new Line(getSlope(), getYInterception());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Set<Line> lines) {
|
||||
this.setOfLines = new ArrayList<>(lines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPresenter(AbstractPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
subscribe(presenter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Steigung
|
||||
*/
|
||||
public double getSlope() {
|
||||
return slope * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y-Achsenabschnitt
|
||||
*/
|
||||
public double getYInterception() {
|
||||
return yInterception * -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
}
|
89
src/main/java/de/wwwu/awolf/presenter/data/DataHandler.java
Normal file
@ -0,0 +1,89 @@
|
||||
package de.wwwu.awolf.presenter.data;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.AbstractPresenter;
|
||||
import de.wwwu.awolf.presenter.data.generator.CircleDatasetGenerator;
|
||||
import de.wwwu.awolf.presenter.data.generator.CloudDatasetGenerator;
|
||||
import de.wwwu.awolf.presenter.data.generator.LineDatasetGenerator;
|
||||
import de.wwwu.awolf.presenter.data.io.DataExporter;
|
||||
import de.wwwu.awolf.presenter.data.io.DataImporter;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
|
||||
public class DataHandler {
|
||||
|
||||
private final AbstractPresenter presenter;
|
||||
|
||||
public DataHandler(AbstractPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
public Set<Line> getData(final File file) {
|
||||
//Presenter soll die Klasse überwachen
|
||||
ExecutorCompletionService<Set<Line>> completionService = new ExecutorCompletionService<>(
|
||||
this.presenter.getExecutor());
|
||||
Logging.logDebug("Importing Data: " + file.getAbsolutePath());
|
||||
completionService.submit(new DataImporter(file));
|
||||
//wait until future is ready
|
||||
try {
|
||||
return completionService.take().get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Logging.logError("Interrupted while importing... ", e);
|
||||
Thread.currentThread().interrupt();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Set<Line> getData(final DataType type, final int dataSize) {
|
||||
//Presenter soll die Klasse überwachen
|
||||
ExecutorCompletionService<Set<Line>> completionService = new ExecutorCompletionService<>(
|
||||
this.presenter.getExecutor());
|
||||
Logging.logDebug("Generating Data: Size: " + dataSize + ", dataType: " + type.name());
|
||||
|
||||
switch (type) {
|
||||
case CIRCLE:
|
||||
completionService.submit(new CircleDatasetGenerator(dataSize));
|
||||
break;
|
||||
case LINE:
|
||||
completionService.submit(new LineDatasetGenerator(dataSize));
|
||||
break;
|
||||
case CLOUD:
|
||||
completionService.submit(new CloudDatasetGenerator(dataSize));
|
||||
break;
|
||||
default:
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
try {
|
||||
return completionService.take().get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Logging.logError("Interrupted while generating... ", e);
|
||||
Thread.currentThread().interrupt();
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
public void exportData(File file, Set<Line> lines) {
|
||||
this.presenter.getExecutor().submit(new DataExporter(lines, file));
|
||||
}
|
||||
|
||||
|
||||
public enum DataType {
|
||||
CLOUD,
|
||||
LINE,
|
||||
CIRCLE
|
||||
}
|
||||
|
||||
public enum ActionType {
|
||||
IMPORT,
|
||||
EXPORT,
|
||||
GENERATE
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package de.wwwu.awolf.presenter.data.generator;
|
||||
|
||||
import static de.wwwu.awolf.presenter.data.generator.DatasetGenerator.generateDataLines;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 01.08.2017.
|
||||
*/
|
||||
public class CircleDatasetGenerator implements Callable<Set<Line>> {
|
||||
|
||||
private final int size;
|
||||
|
||||
public CircleDatasetGenerator(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert einen Datensatz des typen: Gerade mit zirkulärer Störung. Zuerst wird die zirkuläre Störung zu der Liste der (dualen-)Geraden hinzugefügt danach wird die wrapper Methode
|
||||
* <code>generateDataLines()</code> aufgerufen.
|
||||
*
|
||||
* @return Liste der Geraden
|
||||
*/
|
||||
@Override
|
||||
public Set<Line> call() throws Exception {
|
||||
Set<Line> lines = new HashSet<>();
|
||||
|
||||
double from = 0;
|
||||
double to = Math.PI * 5;
|
||||
//obere Grenze für die neuen Punkte
|
||||
int n = size / 2 + lines.size();
|
||||
|
||||
//calculate the distance between every two points
|
||||
double distance = (to - from) / ((double) n);
|
||||
|
||||
//create points
|
||||
double currentDistance = from;
|
||||
//an die aktuelle Liste dranhängen
|
||||
for (int i = lines.size(); i < n; i++) {
|
||||
double x = Math.cos(currentDistance);
|
||||
double y = Math.sin(currentDistance);
|
||||
|
||||
Line line = new Line(x, y);
|
||||
line.setId(i + "");
|
||||
lines.add(line);
|
||||
|
||||
//distance for the next iteration
|
||||
currentDistance += distance;
|
||||
}
|
||||
|
||||
int generateSize = (int) (size * 0.5);
|
||||
|
||||
return generateDataLines(lines, generateSize);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
package de.wwwu.awolf.presenter.data.generator;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 01.08.2017.
|
||||
*/
|
||||
public class CloudDatasetGenerator implements Callable<Set<Line>> {
|
||||
|
||||
private final int size;
|
||||
|
||||
public CloudDatasetGenerator(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert zu einer gegebenen Größe einen Datensatz des typen: Punktwolke
|
||||
*
|
||||
* @return Liste der Geraden
|
||||
*/
|
||||
public Set<Line> generateDataCloud() {
|
||||
Set<Line> lines = new HashSet<>();
|
||||
SecureRandom random = new SecureRandom();
|
||||
double m = 1 + random.nextDouble();
|
||||
double b = random.nextDouble();
|
||||
|
||||
for (int i = 1; i < (size + 1); i++) {
|
||||
double y = (random.nextGaussian() * 100) % 100;
|
||||
double signal = m * i + b;
|
||||
signal *= -1;
|
||||
|
||||
Line line = new Line(i, signal - y);
|
||||
line.setId(i - 1 + "");
|
||||
lines.add(line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Line> call() throws Exception {
|
||||
return generateDataCloud();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
package de.wwwu.awolf.presenter.data.generator;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 01.08.2017.
|
||||
*/
|
||||
public class DatasetGenerator {
|
||||
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*/
|
||||
private DatasetGenerator() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generieren eines Datensatzes des typen: Gerade. Die Geraden werden in eine übergebene Liste hinzugefügt.
|
||||
*
|
||||
* @param n Größe des Datensatzes
|
||||
* @return Liste des Geraden
|
||||
*/
|
||||
public static Set<Line> generateDataLines(Set<Line> lines, int n) {
|
||||
|
||||
double m = 5d;
|
||||
double b = 0d;
|
||||
|
||||
int size = 0;
|
||||
Map<Double, Double> points = new HashMap<>();
|
||||
|
||||
//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;
|
||||
signal *= -1;
|
||||
|
||||
if (!points.containsKey(y)) {
|
||||
points.put(y, signal);
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
int idx = lines.size();
|
||||
for (Map.Entry<Double, Double> d : points.entrySet()) {
|
||||
Line line = new Line(d.getKey(), d.getValue());
|
||||
line.setId(idx + "");
|
||||
lines.add(line);
|
||||
idx++;
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package de.wwwu.awolf.presenter.data.generator;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 01.08.2017.
|
||||
*/
|
||||
public class LineDatasetGenerator implements Callable<Set<Line>> {
|
||||
|
||||
private final int size;
|
||||
|
||||
|
||||
public LineDatasetGenerator(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper Methode zum generieren eines Datensatzes des typen: Gerade
|
||||
*
|
||||
* @return Liste des Geraden
|
||||
*/
|
||||
@Override
|
||||
public Set<Line> call() throws Exception {
|
||||
return DatasetGenerator.generateDataLines(new HashSet<>(), size);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
package de.wwwu.awolf.presenter.data.io;
|
||||
|
||||
import com.opencsv.CSVWriter;
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 03.08.2017.
|
||||
*/
|
||||
public class DataExporter implements Runnable {
|
||||
|
||||
private Set<Line> lines;
|
||||
private File file;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param lines Liste der Geraden
|
||||
* @param file Datei in die, die Informationen exportiert werden sollen
|
||||
*/
|
||||
public DataExporter(Set<Line> lines, File file) {
|
||||
this.file = file;
|
||||
this.lines = lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode schreibt die Geraden der Form: y = mx + b, in eine Komma-Separierte Datei (CSV). Der Aufbau der Datei ist: id, m, b. Wenn der Export beendet wurde wird die Beobachter-Klasse
|
||||
* informiert. In diesem Fall ist dies die Presenter Klasse.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
CSVWriter writer = null;
|
||||
|
||||
try {
|
||||
writer = new CSVWriter(new FileWriter(file));
|
||||
String[] entries = new String[3];
|
||||
for (Line line : lines) {
|
||||
entries[0] = line.getId();
|
||||
entries[1] = line.getM().toString();
|
||||
double tmp = (-1) * line.getB();
|
||||
entries[2] = Double.toString(tmp);
|
||||
writer.writeNext(entries);
|
||||
}
|
||||
writer.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
Logging.logError(e.getMessage(), e);
|
||||
}
|
||||
|
||||
Logging.logInfo(
|
||||
"The model has been successfully saved under: " + file.getAbsolutePath() + ".");
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
package de.wwwu.awolf.presenter.data.io;
|
||||
|
||||
import com.opencsv.CSVReader;
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 21.06.2017.
|
||||
*/
|
||||
public class DataImporter implements Callable<Set<Line>> {
|
||||
|
||||
private CSVReader reader;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param file Datei aus der die Informationen imortiert werden sollen.
|
||||
*/
|
||||
public DataImporter(File file) {
|
||||
|
||||
try {
|
||||
this.reader = new CSVReader(new FileReader(file));
|
||||
} catch (FileNotFoundException e) {
|
||||
Logging.logError(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode importiert liest zeile für zeile die Daten aus der Datei und baut eine Liste von Geraden auf. Dabei wird auf die richtige Form geachtet. Falls die Datei nicht, mindestens zwei
|
||||
* Spalten enthält wird ein Fehler signalisiert und der Import wird abgebrochen.
|
||||
*
|
||||
* @return Liste der Geraden
|
||||
*/
|
||||
@Override
|
||||
public Set<Line> call() throws Exception {
|
||||
Set<Line> list = new HashSet<>();
|
||||
try {
|
||||
List<String[]> lines = reader.readAll();
|
||||
int counter = 0;
|
||||
String[] result = {"import", lines.size() + "", ""};
|
||||
for (String[] nextLine : lines) {
|
||||
if (nextLine.length == 3) {
|
||||
double x = Double.parseDouble(nextLine[1]);
|
||||
double y = Double.parseDouble(nextLine[2]) * (-1);
|
||||
Line line = new Line(x, y);
|
||||
line.setId(nextLine[0] + "");
|
||||
list.add(line);
|
||||
counter++;
|
||||
result[2] = counter + "";
|
||||
Thread.sleep(10);
|
||||
} else if (nextLine.length == 2) {
|
||||
double x = Double.parseDouble(nextLine[1]);
|
||||
double y = Double.parseDouble(nextLine[2]) * (-1);
|
||||
Line line = new Line(x, y);
|
||||
line.setId(counter + "");
|
||||
list.add(line);
|
||||
|
||||
counter++;
|
||||
result[2] = counter + "";
|
||||
Thread.sleep(10);
|
||||
} else {
|
||||
Logging.logWarning(
|
||||
"Diese Datei kann nicht importiert werden. Es müssen mindestens zwei Spalten enthalten sein (x,y). Fehler bei der Eingabe");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Logging.logError(e.getMessage(), e);
|
||||
} catch (InterruptedException e) {
|
||||
Logging.logError(e.getMessage(), e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package de.wwwu.awolf.presenter.evaluation;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.model.evaluation.ComparisonResult;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.algorithms.AlgorithmHandler;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class AlgorithmComparison {
|
||||
|
||||
private final List<Algorithm.Type> types;
|
||||
private final ExecutorService executorService;
|
||||
private final CompletionService<Line> completionService;
|
||||
private final Set<Line> lines;
|
||||
|
||||
public AlgorithmComparison(List<Algorithm.Type> types, Set<Line> lines) {
|
||||
this.types = types;
|
||||
this.lines = lines;
|
||||
this.executorService = Executors.newFixedThreadPool(3);
|
||||
completionService = new ExecutorCompletionService<>(this.executorService);
|
||||
}
|
||||
|
||||
public ComparisonResult compare() {
|
||||
|
||||
ComparisonResult comparisonResult = new ComparisonResult();
|
||||
AlgorithmHandler algorithmHandler = AlgorithmHandler.getInstance();
|
||||
|
||||
for (Algorithm.Type value : getTypes()) {
|
||||
Algorithm.Type type;
|
||||
synchronized (types) {
|
||||
type = value;
|
||||
}
|
||||
|
||||
Line line = algorithmHandler.runAlgorithmByType(type, lines);
|
||||
comparisonResult.put(type, line);
|
||||
}
|
||||
return comparisonResult;
|
||||
}
|
||||
|
||||
private List<Algorithm.Type> getTypes() {
|
||||
return types;
|
||||
}
|
||||
}
|
@ -0,0 +1,282 @@
|
||||
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<Data> {
|
||||
|
||||
private LineModel arrangement;
|
||||
private DatasetGenerator generator;
|
||||
|
||||
//übergebene Parameter
|
||||
private int type;
|
||||
private int iterations;
|
||||
private int alg;
|
||||
private Flow.Subscriber<? super Data> subscriber;
|
||||
private Map<Algorithm.Type, Map<String, String>> 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<Line> 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<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.unmodifiableSet(arrangement.getLines()));
|
||||
ComparisonResult comparisonResult = comparison.compare();
|
||||
|
||||
Map<String, String> 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<Algorithm.Type, Map<String, String>> benchmarkDifferentEstimators(
|
||||
List<Algorithm.Type> 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<Algorithm.Type, Map<String, String>> 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<Algorithm.Type, Map<String, String>> 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<String, String> getScaleDependentMeasure(final Set<Line> 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<String, String> 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<String, String> getPercentigeErrorBasedMeasure(final Set<Line> 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<String, String> 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<String, String> getScaledErrorBasedMeasure(final Set<Line> 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<String, String> 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<Line> getData() {
|
||||
return arrangement.getLines();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(Flow.Subscriber<? super Data> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package de.wwwu.awolf.presenter.evaluation.measures;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.util.FastElementSelector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 07.09.2017.
|
||||
*/
|
||||
public class PercentageErrorBasedMeasure {
|
||||
|
||||
|
||||
private List<Double> percentageError;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param lines Liste der Geraden
|
||||
* @param m Steigung
|
||||
* @param b y-Achenabschnitt
|
||||
*/
|
||||
public PercentageErrorBasedMeasure(final Set<Line> lines, Double m, Double b) {
|
||||
|
||||
//Berechnung des Sampson-Fehlers
|
||||
List<Line> linesAsList = new ArrayList<>(lines);
|
||||
List<Double> sampson = new ArrayList<>();
|
||||
for (Line line : linesAsList) {
|
||||
Double e = Math.pow(m * line.getM() - line.getB() + b, 2) / (Math.pow(m, 2) + 1);
|
||||
sampson.add(e);
|
||||
}
|
||||
|
||||
percentageError = new ArrayList<>();
|
||||
//Berechnung der prozentuelen-Fehlers
|
||||
for (int j = 0; j < sampson.size(); j++) {
|
||||
percentageError.add(100 * sampson.get(j) / linesAsList.get(j).getB());
|
||||
}
|
||||
}
|
||||
|
||||
/* Percentege Error Approximation Measures */
|
||||
//verschiedene Eingaben für einen Alg.
|
||||
|
||||
/**
|
||||
* Mean Absolute Precentage Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double mape() {
|
||||
double error = 0;
|
||||
|
||||
for (Double d : percentageError) {
|
||||
error += Math.abs(d);
|
||||
}
|
||||
|
||||
error /= percentageError.size();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Median Absolute Precentage Error:
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double mdape() {
|
||||
|
||||
ArrayList<Double> abs = new ArrayList<>();
|
||||
|
||||
for (Double d : percentageError) {
|
||||
abs.add(Math.abs(d));
|
||||
}
|
||||
|
||||
return FastElementSelector.randomizedSelect(abs, abs.size() * 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Root Mean Square Percentage Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double rmspe() {
|
||||
double error = 0;
|
||||
|
||||
for (Double d : percentageError) {
|
||||
error += Math.pow(d, 2);
|
||||
}
|
||||
|
||||
error /= percentageError.size();
|
||||
|
||||
return Math.sqrt(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Root Median Square Percentage Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double rmdspe() {
|
||||
List<Double> squares = new ArrayList<>();
|
||||
for (Double d : percentageError) {
|
||||
squares.add(Math.pow(d, 2));
|
||||
}
|
||||
|
||||
return Math.sqrt(FastElementSelector.randomizedSelect(squares, squares.size() * 0.5));
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package de.wwwu.awolf.presenter.evaluation.measures;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.util.FastElementSelector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 07.09.2017.
|
||||
*/
|
||||
public class ScaleDependentMeasure {
|
||||
|
||||
private Set<Double> errorValues;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param lines Liste des Geraden
|
||||
* @param m Steigung
|
||||
* @param b y-Achsenabschnitt
|
||||
*/
|
||||
public ScaleDependentMeasure(final Set<Line> lines, Double m, Double b) {
|
||||
//Liste mit den Fehler zu jedem Punkt
|
||||
errorValues = new HashSet<>();
|
||||
|
||||
//Sampson-Fehler Berechnung
|
||||
for (Line line : lines) {
|
||||
Double e = Math.pow(m * line.getM() - line.getB() + b, 2) / (Math.pow(m, 2) + 1);
|
||||
errorValues.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Skalierungs Abhängige Approximationsgüten */
|
||||
//unterschiedliche Alg.- auf einem Datensatz
|
||||
|
||||
/**
|
||||
* Mean Square Error:
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double mse() {
|
||||
double error = 0;
|
||||
|
||||
for (Double d : errorValues) {
|
||||
error += Math.pow(d, 2);
|
||||
}
|
||||
|
||||
error /= errorValues.size();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Root Mean Square Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double rmse() {
|
||||
return Math.sqrt(mse());
|
||||
}
|
||||
|
||||
/**
|
||||
* Mean Absolute Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double mae() {
|
||||
double error = 0;
|
||||
for (Double d : errorValues) {
|
||||
error += Math.abs(d);
|
||||
}
|
||||
error /= errorValues.size();
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Median Absolute Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double mdae() {
|
||||
return FastElementSelector
|
||||
.randomizedSelect(new ArrayList<>(errorValues), errorValues.size() * 0.5);
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package de.wwwu.awolf.presenter.evaluation.measures;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.util.FastElementSelector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 07.09.2017.
|
||||
*/
|
||||
public class ScaledErrorBasedMeasure {
|
||||
|
||||
|
||||
private ArrayList<Double> sampsonError;
|
||||
private ArrayList<Double> naivSampsonError;
|
||||
private ArrayList<Double> scaledError;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*
|
||||
* @param lines Liste der Geraden
|
||||
* @param m Steigung
|
||||
* @param b y-Achsenabschnitt
|
||||
* @param naivSlope naive Steigung
|
||||
* @param naivInterception naiver y-Achsenabschnitt
|
||||
*/
|
||||
public ScaledErrorBasedMeasure(final Set<Line> lines, Double m, Double b, Double naivSlope,
|
||||
Double naivInterception) {
|
||||
|
||||
this.sampsonError = new ArrayList<>();
|
||||
this.naivSampsonError = new ArrayList<>();
|
||||
this.scaledError = new ArrayList<>();
|
||||
|
||||
//Sampson-Fehler der naiven Mehtode
|
||||
for (Line line : lines) {
|
||||
Double e =
|
||||
Math.pow(naivSlope * line.getM() - line.getB() + naivInterception, 2) / (
|
||||
Math.pow(naivSlope, 2) + 1);
|
||||
naivSampsonError.add(e);
|
||||
}
|
||||
|
||||
//Sampson-Fehler der fortgeschrittenen Methode
|
||||
for (Line line : lines) {
|
||||
Double e = Math.pow(m * line.getM() - line.getB() + b, 2) / (Math.pow(m, 2) + 1);
|
||||
sampsonError.add(e);
|
||||
}
|
||||
|
||||
//skalierungs-Fehler
|
||||
for (int i = 0; i < sampsonError.size(); i++) {
|
||||
scaledError.add(sampsonError.get(i) / naivSampsonError.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
/* Skalierungs Abhängige Approximationsgüten */
|
||||
//unterschiedliche Alg.- auf einem Datensatz
|
||||
|
||||
/**
|
||||
* Mean Square Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double mse() {
|
||||
double error = 0;
|
||||
for (Double d : scaledError) {
|
||||
error += Math.pow(d, 2);
|
||||
}
|
||||
error /= scaledError.size();
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Root Mean Square Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double rmse() {
|
||||
return Math.sqrt(mse());
|
||||
}
|
||||
|
||||
/**
|
||||
* Mean Absolute Error:
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double mae() {
|
||||
double error = 0;
|
||||
for (Double d : scaledError) {
|
||||
error += Math.abs(d);
|
||||
}
|
||||
error /= scaledError.size();
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Median Absolute Error
|
||||
*
|
||||
* @return Ergebnis
|
||||
*/
|
||||
public Double mdae() {
|
||||
return FastElementSelector
|
||||
.randomizedSelect(scaledError, scaledError.size() * 0.5);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package de.wwwu.awolf.presenter.util;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 26.06.2017.
|
||||
*/
|
||||
public class BinomialCoeffizient {
|
||||
|
||||
/**
|
||||
* Berechnet den Binomialkoeffizient zu der eingabe. Bin(n,k)
|
||||
*
|
||||
* @param n n
|
||||
* @param k k
|
||||
* @return Ergebnis
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package de.wwwu.awolf.presenter.util.Comparators;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 19.06.2017.
|
||||
*/
|
||||
public class YOrderLineComparatorBegin implements Comparator<Line> {
|
||||
|
||||
@Override
|
||||
public int compare(Line o1, Line o2) {
|
||||
return o1.getY1().compareTo(o2.getY1());
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package de.wwwu.awolf.presenter.util.Comparators;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 19.06.2017.
|
||||
*/
|
||||
public class YOrderLineComparatorEnd implements Comparator<Line> {
|
||||
|
||||
@Override
|
||||
public int compare(Line o1, Line o2) {
|
||||
return o1.getY2().compareTo(o2.getY2());
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package de.wwwu.awolf.presenter.util;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 29.06.2017.
|
||||
*/
|
||||
public class FastElementSelector {
|
||||
|
||||
/**
|
||||
* Liefert das k-te Element aus der Eingabeliste zurück in Theta(n) Zeit.
|
||||
*
|
||||
* @param a Eingabeliste
|
||||
* @param i Rang des gewünschten Elements
|
||||
* @return das Element
|
||||
*/
|
||||
public static Double randomizedSelect(List<Double> a, double i) {
|
||||
|
||||
int start = 0;
|
||||
int end = a.size() - 1;
|
||||
|
||||
if (i >= end + 1) {
|
||||
return a.get(end);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (start >= end) {
|
||||
return a.get(start);
|
||||
}
|
||||
int q = randomizedPartition(a, start, end);
|
||||
int k = q - start + 1;
|
||||
|
||||
if (i == k) {
|
||||
return a.get(q);
|
||||
} else {
|
||||
if (i < k) {
|
||||
end = q - 1;
|
||||
} else {
|
||||
start = q + 1;
|
||||
i = i - k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode
|
||||
*
|
||||
* @param a Eingabeliste
|
||||
* @param start Startindex
|
||||
* @param end Index des letzten Elements
|
||||
* @return Pivotelement
|
||||
*/
|
||||
private static int randomizedPartition(List<Double> a, int start, int end) {
|
||||
int i = 0;
|
||||
SecureRandom random = new SecureRandom();
|
||||
|
||||
//alternative: ThreadLocalRandom.current()
|
||||
if (start < end) {
|
||||
i = start + random.nextInt(end - start);
|
||||
} else {
|
||||
i = end + random.nextInt(start - end);
|
||||
}
|
||||
|
||||
Collections.swap(a, end, i);
|
||||
return partition(a, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hilfsmethode
|
||||
*
|
||||
* @param a Eingabeliste
|
||||
* @param start Startindex
|
||||
* @param end Index des letzten Elements
|
||||
* @return Pivotelement
|
||||
*/
|
||||
private static int partition(List<Double> a, int start, int end) {
|
||||
Double x = a.get(end);
|
||||
int i = start - 1;
|
||||
for (int j = start; j <= end - 1; j++) {
|
||||
if (a.get(j) <= x) {
|
||||
i++;
|
||||
Collections.swap(a, i, j);
|
||||
}
|
||||
}
|
||||
Collections.swap(a, i + 1, end);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
package de.wwwu.awolf.presenter.util;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.model.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 18.09.2017.
|
||||
*/
|
||||
public class IntersectionComputer {
|
||||
|
||||
private static IntersectionComputer instance;
|
||||
|
||||
/**
|
||||
* Konstruktor
|
||||
*/
|
||||
private IntersectionComputer() {
|
||||
}
|
||||
|
||||
public static IntersectionComputer getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new IntersectionComputer();
|
||||
Logging.logInfo("Created instance of IntersectionComputer");
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @param lower untere Schranke
|
||||
* @param higher obere Schranke
|
||||
* @return Liste der Schnittpunkte
|
||||
*/
|
||||
public Set<Point> compute(final Collection<Line> lines, final double lower,
|
||||
final double higher) {
|
||||
|
||||
final Set<Line> fullInput = new HashSet<>(lines);
|
||||
final Set<Line> copyInput = new HashSet<>(lines);
|
||||
|
||||
if (lower == higher) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
Logging.logDebug(
|
||||
"Open ForkJoinPool: lines: " + lines.size() + " I(" + lower + ", " + higher
|
||||
+ "]");
|
||||
ForkJoinPool pool = ForkJoinPool.commonPool();
|
||||
RecursiveComputationTask recursiveComputationTask = new RecursiveComputationTask(
|
||||
fullInput,
|
||||
copyInput, lower, higher);
|
||||
pool.execute(recursiveComputationTask);
|
||||
Set<Point> join = recursiveComputationTask.join();
|
||||
return join;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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> calculateIntersectionAbscissas(Collection<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).getX());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(intersections);
|
||||
}
|
||||
|
||||
private class RecursiveComputationTask extends RecursiveTask<Set<Point>> {
|
||||
|
||||
private static final int THRESHOLD = 200;
|
||||
|
||||
private final Set<Line> lines;
|
||||
private final Set<Line> fullList;
|
||||
private final double lower;
|
||||
private final double upper;
|
||||
|
||||
public RecursiveComputationTask(final Set<Line> fullList, final Set<Line> lines,
|
||||
final double lower, final double upper) {
|
||||
this.lines = lines;
|
||||
this.fullList = fullList;
|
||||
this.lower = lower;
|
||||
this.upper = upper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Point> compute() {
|
||||
if (this.lines.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
} else if (this.lines.size() > THRESHOLD) {
|
||||
return ForkJoinTask.invokeAll(createSubTask()).stream()
|
||||
.map(ForkJoinTask::join)
|
||||
.flatMap(Collection::stream).collect(Collectors.toSet());
|
||||
} else {
|
||||
return work(this.fullList, this.lines, this.lower, this.upper);
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<RecursiveComputationTask> createSubTask() {
|
||||
List<RecursiveComputationTask> dividedTasks = new ArrayList<>();
|
||||
|
||||
long midpoint = Math.round(this.lines.size() * 0.5);
|
||||
|
||||
Set<Line> firstSubSet = new HashSet<>();
|
||||
Set<Line> secondSubSet = new HashSet<>();
|
||||
AtomicInteger count = new AtomicInteger();
|
||||
this.lines.forEach(next -> {
|
||||
int index = count.getAndIncrement();
|
||||
if (index < midpoint) {
|
||||
firstSubSet.add(next);
|
||||
} else {
|
||||
secondSubSet.add(next);
|
||||
}
|
||||
});
|
||||
|
||||
dividedTasks
|
||||
.add(new RecursiveComputationTask(this.fullList, firstSubSet, this.lower,
|
||||
this.upper));
|
||||
dividedTasks
|
||||
.add(new RecursiveComputationTask(this.fullList, secondSubSet, this.lower,
|
||||
this.upper));
|
||||
return dividedTasks;
|
||||
}
|
||||
|
||||
private Set<Point> work(Set<Line> fullList, Set<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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
50
src/main/java/de/wwwu/awolf/presenter/util/Logging.java
Normal file
@ -0,0 +1,50 @@
|
||||
package de.wwwu.awolf.presenter.util;
|
||||
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class Logging {
|
||||
|
||||
private static Logger logger = Logger.getRootLogger();
|
||||
|
||||
private Logging() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
public static void logInfo(final String message, Throwable throwable) {
|
||||
logger.info(message, throwable);
|
||||
}
|
||||
|
||||
public static void logInfo(final String message) {
|
||||
logger.info(message);
|
||||
}
|
||||
|
||||
public static void logDebug(final String message, Throwable throwable) {
|
||||
logger.debug(message, throwable);
|
||||
}
|
||||
|
||||
public static void logDebug(final String message) {
|
||||
logger.debug(message);
|
||||
}
|
||||
|
||||
public static void logWarning(final String message, Throwable throwable) {
|
||||
logger.warn(message, throwable);
|
||||
}
|
||||
|
||||
public static void logWarning(final String message) {
|
||||
logger.warn(message);
|
||||
}
|
||||
|
||||
public static void logError(final String message, Throwable throwable) {
|
||||
logger.error(message, throwable);
|
||||
}
|
||||
|
||||
public static void logError(final String message) {
|
||||
logger.error(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package de.wwwu.awolf.presenter.util;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 26.06.2017.
|
||||
*/
|
||||
public class RandomSampler {
|
||||
|
||||
private static SecureRandom random = new SecureRandom(); // Compliant for security-sensitive use cases
|
||||
|
||||
private RandomSampler() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Diese Methode liefert eine <code>r</code> Elementige zufällige Stichprobe an Geraden.
|
||||
*
|
||||
* @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 Geraden
|
||||
*/
|
||||
public static <T extends Object> List<T> run(List<T> set, Double r) {
|
||||
if (set.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
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 sampled;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
213
src/main/java/de/wwwu/awolf/view/ViewController.java
Normal file
@ -0,0 +1,213 @@
|
||||
package de.wwwu.awolf.view;
|
||||
|
||||
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.DataHandler;
|
||||
import de.wwwu.awolf.presenter.util.Logging;
|
||||
import de.wwwu.awolf.view.controller.AlgorithmTabController;
|
||||
import de.wwwu.awolf.view.services.DataService;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.control.Menu;
|
||||
import javafx.scene.control.MenuBar;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 28.05.2017.
|
||||
*/
|
||||
public class ViewController {
|
||||
|
||||
private static final String TITLE = "Beta JavaFX";
|
||||
private Parent pane;
|
||||
|
||||
@FXML
|
||||
private TabPane tabPane;
|
||||
@FXML
|
||||
private MenuBar menuBar;
|
||||
private Map<Algorithm.Type, AlgorithmTabController> algorithmTabControllers;
|
||||
|
||||
public ViewController() {
|
||||
super();
|
||||
this.algorithmTabControllers = new EnumMap<>(Algorithm.Type.class);
|
||||
}
|
||||
|
||||
public Map<Algorithm.Type, AlgorithmTabController> getAlgorithmTabControllers() {
|
||||
return algorithmTabControllers;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
initMenuBar();
|
||||
initTabbedPane();
|
||||
}
|
||||
|
||||
private void initTabbedPane() {
|
||||
//TODO
|
||||
Map<String, String> props = new HashMap<>();
|
||||
props.put("sfsdf", "dsadasd");
|
||||
props.put("dfd", "dsadasd");
|
||||
props.put("sdfdsfg", "dsadasd");
|
||||
props.put("dsfsdfsdf", "dsadasd");
|
||||
|
||||
try {
|
||||
for (Algorithm.Type value : Algorithm.Type.values()) {
|
||||
FXMLLoader loader = new FXMLLoader();
|
||||
loader.setLocation(
|
||||
AlgorithmTabController.class.getResource("/views/AlgorithmTab.fxml"));
|
||||
Parent parent = loader.load();
|
||||
AlgorithmTabController controller = loader.getController();
|
||||
controller.setAlgorithmType(value);
|
||||
controller.setProperties(props);
|
||||
controller.setModel(Presenter.getInstance().getModel());
|
||||
controller.init();
|
||||
this.algorithmTabControllers.put(value, controller);
|
||||
Tab tab = new Tab(value.getLabel(), parent);
|
||||
tab.setId(value.name());
|
||||
tabPane.getTabs().add(tab);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
Logging.logError("Error while reading AlgorithmTab.fxml", e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void initMenuBar() {
|
||||
// Create menus
|
||||
Menu fileMenu = new Menu("File");
|
||||
Menu toolsMenu = new Menu("Tools");
|
||||
Menu helpMenu = new Menu("Help");
|
||||
|
||||
// Create MenuItems
|
||||
//export the data
|
||||
MenuItem exportItem = new MenuItem("Export");
|
||||
exportItem.setOnAction(actionEvent -> {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
File file = fileChooser.showOpenDialog(null);
|
||||
if (file != null && file.canWrite() && file.canRead()) {
|
||||
new DataService(DataHandler.ActionType.EXPORT, file).start();
|
||||
}
|
||||
});
|
||||
|
||||
//start an import of data
|
||||
MenuItem importItem = new MenuItem("Import");
|
||||
importItem.setOnAction(actionEvent -> {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
File file = fileChooser.showOpenDialog(null);
|
||||
if (file != null && file.canWrite() && file.canRead()) {
|
||||
new DataService(DataHandler.ActionType.IMPORT, file).start();
|
||||
}
|
||||
});
|
||||
|
||||
//exit menu item should stop the application
|
||||
MenuItem exitItem = new MenuItem("Exit");
|
||||
exitItem.setOnAction(actionEvent -> {
|
||||
Platform.exit();
|
||||
System.exit(0);
|
||||
});
|
||||
|
||||
// about the application
|
||||
MenuItem aboutItem = new MenuItem("About");
|
||||
|
||||
MenuItem generationItem = new MenuItem("Generate");
|
||||
generationItem.setOnAction(actionEvent -> {
|
||||
new DataService(DataHandler.ActionType.GENERATE, DataHandler.DataType.LINE, 1000)
|
||||
.start();
|
||||
});
|
||||
MenuItem evaluationItem = new MenuItem("Evaluate");
|
||||
|
||||
// Add menuItems to the Menus
|
||||
fileMenu.getItems().addAll(importItem, exportItem, exitItem);
|
||||
toolsMenu.getItems().addAll(generationItem, evaluationItem);
|
||||
helpMenu.getItems().addAll(aboutItem);
|
||||
|
||||
// Add Menus to the MenuBar
|
||||
menuBar.getMenus().addAll(fileMenu, toolsMenu, helpMenu);
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************************************************
|
||||
* visualisierungs methoden
|
||||
******************************************************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* Visualisiert das Ergebnis des LMS-Schätzers
|
||||
*
|
||||
* @param line Line
|
||||
*/
|
||||
public void visualizeLMS(final Line line) {
|
||||
// plotLMS = new PlotPanel();
|
||||
// lmsPanel.setPlotPanel(plotLMS);
|
||||
// createPlot(line.getM(), line.getB(), plotLMS, lmsPanel, "LMS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Visualisiert das Ergebnis des RM-Schätzers
|
||||
*
|
||||
* @param line Line
|
||||
*/
|
||||
public void visualizeRM(final Line line) {
|
||||
// plotRM = new PlotPanel();
|
||||
// rmPanel.setPlotPanel(plotRM);
|
||||
// createPlot(line.getM(), line.getB(), plotRM, rmPanel, "RM");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Visualisiert das Ergebnis des TS-Schätzers
|
||||
*
|
||||
* @param line Line
|
||||
*/
|
||||
public void visualizeTS(final Line line) {
|
||||
// plotTS = new PlotPanel();
|
||||
// tsPanel.setPlotPanel(plotTS);
|
||||
// createPlot(line.getM(), line.getB(), plotTS, tsPanel, "TS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt der Evaluations-Tabelle eine Zeile mit Daten hinzu
|
||||
*
|
||||
* @param tableEntries Data of the Table
|
||||
*/
|
||||
public void appendEvalResult(Map<Algorithm.Type, Map<String, String>> tableEntries) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt der Evaluations-Tabelle eine Zeile mit Daten hinzu
|
||||
*
|
||||
* @param res Daten der Spalte
|
||||
*/
|
||||
public void appendEvalResults(Map<Algorithm.Type, Map<String, String>> res) {
|
||||
appendEvalResult(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Funktionalitäten werden aktiviert.
|
||||
*/
|
||||
public void enableFunctionality() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Funktionalitäten werden deaktiviert.
|
||||
*/
|
||||
public void disableFunctionality() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package de.wwwu.awolf.view.controller;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.model.LineModel;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.view.services.ButtonClickService;
|
||||
import java.util.Map;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.chart.LineChart;
|
||||
import javafx.scene.chart.XYChart;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
public class AlgorithmTabController {
|
||||
|
||||
private final XYChart.Series<Double, Double> dataSerie;
|
||||
private final XYChart.Series<Double, Double> lineSerie;
|
||||
@FXML
|
||||
public LineChart<Double, Double> chart;
|
||||
@FXML
|
||||
public VBox vBox;
|
||||
@FXML
|
||||
public Button startButton;
|
||||
private Algorithm.Type algorithmType;
|
||||
private Map<String, String> properties;
|
||||
private LineModel model;
|
||||
|
||||
public AlgorithmTabController() {
|
||||
dataSerie = new XYChart.Series<>();
|
||||
dataSerie.setName("Datapoints");
|
||||
lineSerie = new XYChart.Series<>();
|
||||
lineSerie.setName("Estimated Line");
|
||||
}
|
||||
|
||||
public LineModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public void setModel(LineModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
// add GUI elements to maintain the parameters
|
||||
properties.forEach((key, value) -> {
|
||||
//Pane component for the layout
|
||||
BorderPane borderPane = new BorderPane();
|
||||
borderPane.setPadding(new Insets(10, 0, 10, 0));
|
||||
|
||||
//text field for the input
|
||||
TextField textField = new TextField(value);
|
||||
|
||||
//label
|
||||
Label label = new Label(key);
|
||||
label.setAlignment(Pos.BASELINE_LEFT);
|
||||
label.setLabelFor(textField);
|
||||
label.setPadding(new Insets(2, 10, 0, 0));
|
||||
|
||||
//add components
|
||||
borderPane.setLeft(label);
|
||||
borderPane.setRight(textField);
|
||||
vBox.getChildren().add(borderPane);
|
||||
});
|
||||
|
||||
BooleanProperty booleanProperty = startButton.disableProperty();
|
||||
startButton.setOnAction(event -> {
|
||||
ButtonClickService buttonClickService = new ButtonClickService(algorithmType,
|
||||
booleanProperty);
|
||||
buttonClickService.start();
|
||||
}
|
||||
);
|
||||
|
||||
updatePlot(this.model, null);
|
||||
chart.getData().add(dataSerie);
|
||||
chart.getData().add(lineSerie);
|
||||
}
|
||||
|
||||
public void updatePlot(final LineModel model, final Line pLine) {
|
||||
dataSerie.getData().clear();
|
||||
model.getLines()
|
||||
.forEach(
|
||||
line -> dataSerie.getData().add(new XYChart.Data<>(line.getM(), line.getB())));
|
||||
|
||||
if (pLine != null) {
|
||||
lineSerie.getData().clear();
|
||||
Double x1 = pLine.calculateX1(model.getMin());
|
||||
Double y1 = pLine.calculateY1(model.getMin());
|
||||
Double x2 = pLine.calculateX2(model.getMax());
|
||||
Double y2 = pLine.calculateY2(model.getMax());
|
||||
|
||||
lineSerie.getData().add(new XYChart.Data<>(x1, y1));
|
||||
lineSerie.getData().add(new XYChart.Data<>(x2, y2));
|
||||
}
|
||||
}
|
||||
|
||||
public Algorithm.Type getAlgorithmType() {
|
||||
return algorithmType;
|
||||
}
|
||||
|
||||
public void setAlgorithmType(Algorithm.Type algorithmType) {
|
||||
this.algorithmType = algorithmType;
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, String> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package de.wwwu.awolf.view.services;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.Presenter;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
|
||||
public class ButtonClickService extends Service<Boolean> {
|
||||
|
||||
private final BooleanProperty startButtonDisabled;
|
||||
private Algorithm.Type type;
|
||||
|
||||
public ButtonClickService(Algorithm.Type algorithmType, BooleanProperty startButtonDisabled) {
|
||||
this.startButtonDisabled = startButtonDisabled;
|
||||
this.type = algorithmType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<Boolean> createTask() {
|
||||
|
||||
return new Task<Boolean>() {
|
||||
@Override
|
||||
protected Boolean call() throws Exception {
|
||||
try {
|
||||
Line line = Presenter.getInstance()
|
||||
.executeAlgorithmByType(type, startButtonDisabled);
|
||||
if (line != null) {
|
||||
return true;
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
51
src/main/java/de/wwwu/awolf/view/services/DataService.java
Normal file
@ -0,0 +1,51 @@
|
||||
package de.wwwu.awolf.view.services;
|
||||
|
||||
import de.wwwu.awolf.presenter.Presenter;
|
||||
import de.wwwu.awolf.presenter.data.DataHandler;
|
||||
import java.io.File;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
|
||||
public class DataService extends Service<Boolean> {
|
||||
|
||||
private File file;
|
||||
private DataHandler.DataType type;
|
||||
private DataHandler.ActionType actionType;
|
||||
private int n;
|
||||
|
||||
public DataService(final DataHandler.ActionType actionType, final DataHandler.DataType type,
|
||||
final int n) {
|
||||
this.type = type;
|
||||
this.actionType = actionType;
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
public DataService(final DataHandler.ActionType actionType, final File file) {
|
||||
this.actionType = actionType;
|
||||
this.file = file;
|
||||
this.type = null;
|
||||
this.n = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<Boolean> createTask() {
|
||||
return new Task<>() {
|
||||
@Override
|
||||
protected Boolean call() throws Exception {
|
||||
switch (actionType) {
|
||||
case EXPORT:
|
||||
Presenter.getInstance().exportDataset(file);
|
||||
break;
|
||||
case IMPORT:
|
||||
Presenter.getInstance().importDataset(file);
|
||||
break;
|
||||
case GENERATE:
|
||||
Presenter.getInstance().generateDataset(n, type);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package de.wwwu.awolf.view.services;
|
||||
|
||||
import de.wwwu.awolf.presenter.Presenter;
|
||||
import de.wwwu.awolf.view.ViewController;
|
||||
import javafx.concurrent.Service;
|
||||
import javafx.concurrent.Task;
|
||||
|
||||
public class GuiRegisterService extends Service<Boolean> {
|
||||
|
||||
private final ViewController view;
|
||||
|
||||
|
||||
public GuiRegisterService(final ViewController view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<Boolean> createTask() {
|
||||
return new Task<>() {
|
||||
@Override
|
||||
protected Boolean call() throws Exception {
|
||||
Presenter.getInstance().registerView(view);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
de.wwwu.awolf.presenter.algorithms.advanced.LeastMedianOfSquaresEstimator
|
||||
de.wwwu.awolf.presenter.algorithms.advanced.RepeatedMedianEstimator
|
||||
de.wwwu.awolf.presenter.algorithms.advanced.TheilSenEstimator
|
||||
de.wwwu.awolf.presenter.algorithms.naiv.NaivLeastMedianOfSquaresEstimator
|
||||
de.wwwu.awolf.presenter.algorithms.naiv.NaivRepeatedMedianEstimator
|
||||
de.wwwu.awolf.presenter.algorithms.naiv.NaivTheilSenEstimator
|
BIN
src/main/resources/Thumbs.db
Normal file
BIN
src/main/resources/icons/export.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/main/resources/icons/frame-2.png
Normal file
After Width: | Height: | Size: 764 B |
BIN
src/main/resources/icons/frame.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
src/main/resources/icons/generate.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
src/main/resources/icons/import.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
src/main/resources/icons/plot.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/main/resources/icons/start.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
src/main/resources/icons/wwu.png
Normal file
After Width: | Height: | Size: 18 KiB |
14
src/main/resources/log4j.properties
Normal file
@ -0,0 +1,14 @@
|
||||
# Root logger option
|
||||
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
|
||||
log4j.appender.file.MaxFileSize=10MB
|
||||
log4j.appender.file.MaxBackupIndex=10
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} [%t] - %m%n
|
||||
# Direct log messages to stdout
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss} [%t] - %m%n
|
340
src/main/resources/style/style.css
Normal file
@ -0,0 +1,340 @@
|
||||
|
||||
/**
|
||||
* JavaFX CSS Brume, light grey/white theme.
|
||||
*/
|
||||
.root {
|
||||
-fx-background-color: derive(#1d1d1d,20%);
|
||||
}
|
||||
|
||||
|
||||
.titled-pane {
|
||||
-fx-effect: dropshadow(three-pass-box, #9F9F9F, 15, 0, 0, 0);
|
||||
-fx-animated: true;
|
||||
-fx-text-fill: #505050;
|
||||
}
|
||||
|
||||
.titled-pane .title {
|
||||
-fx-background-radius: 0, 0, 0;
|
||||
-fx-font: bold 14px System;
|
||||
-fx-padding: 0.3em 0.833333em 0.35em 0.833333em;
|
||||
|
||||
/* stop the background from being blue on focus */
|
||||
-fx-background-color: ladder(
|
||||
red,
|
||||
black 20%,
|
||||
derive(#d0d0d0,-30%) 30%
|
||||
),
|
||||
linear-gradient(
|
||||
to bottom,
|
||||
ladder(#d0d0d0,
|
||||
derive(#d0d0d0,80%) 60%,
|
||||
white 82%) 0%,
|
||||
ladder(#d0d0d0,
|
||||
derive(#d0d0d0,20%) 10%,
|
||||
derive(#d0d0d0,-10%) 80%) 100%
|
||||
), linear-gradient(
|
||||
to bottom,
|
||||
derive(#d0d0d0,34%) 0%,
|
||||
derive(#d0d0d0,-18%) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.titled-pane:focused > .title > .arrow-button .arrow {
|
||||
/* do not highlight the title pane arrow on focus */
|
||||
-fx-background-color: #606060;
|
||||
}
|
||||
|
||||
.tree-cell:odd {
|
||||
/* shade every other line in a tree view */
|
||||
-fx-background-color: derive(-fx-control-inner-background,-5%);
|
||||
}
|
||||
|
||||
/* the previous css to shade every other cell overrides the selection
|
||||
colour, so put it back for odd cells */
|
||||
.tree-view:focused .tree-cell:filled:focused:selected:odd{
|
||||
-fx-background-color: -fx-focus-color, -fx-cell-focus-inner-border, -fx-selection-bar;
|
||||
}
|
||||
|
||||
/* if you have labels within your tree nodes, then make the text light so
|
||||
that it stands out from the selection colour. */
|
||||
.tree-view:focused .tree-cell:filled:focused:selected:odd .label {
|
||||
-fx-text-fill: -fx-light-text-color;
|
||||
}
|
||||
.tree-view:focused .tree-cell:filled:focused:selected:even .label {
|
||||
-fx-text-fill: -fx-light-text-color;
|
||||
}
|
||||
|
||||
.button {
|
||||
/* buttons do not have rounded corners */
|
||||
-fx-background-radius: 0;
|
||||
-fx-label-padding: 0.3em 0.833333em 0.35em 0.833333em;
|
||||
}
|
||||
|
||||
.menu-button {
|
||||
/* the left side of the menu button is not rounded */
|
||||
}
|
||||
|
||||
.menu-button .label {
|
||||
-fx-label-padding: 0.23em 0.2em 0.24em 0.2em;
|
||||
}
|
||||
|
||||
.combo-box-base {
|
||||
/* the left side of the combo box is not rounded */
|
||||
-fx-background-radius: 0 5 5 0, 0 5 5 0, 0 4 4 0, 0 3 3 0;
|
||||
}
|
||||
|
||||
.combo-box .list-cell {
|
||||
/* -fx-padding: 6 6 6 6; */
|
||||
}
|
||||
|
||||
/* make the tooltip a slightly transparent black rectange with white text */
|
||||
.tooltip {
|
||||
-fx-background-color: black;
|
||||
-fx-opacity: 0.6;
|
||||
-fx-background-insets: 0,1,2;
|
||||
-fx-background-radius: 0;
|
||||
-fx-padding: 0.333333em 0.666667em 0.333333em 0.666667em; /* 4 8 4 8 */
|
||||
-fx-wrap-text:false;
|
||||
}
|
||||
.tooltip .label {
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
/* remove the turned page effect */
|
||||
.page-corner {
|
||||
-fx-padding: 0;
|
||||
-fx-background-color: null;
|
||||
-fx-shape: null;
|
||||
-fx-effect: null;
|
||||
}
|
||||
|
||||
.toggle-button {
|
||||
-fx-background-radius: 0;
|
||||
-fx-label-padding: 0.3em 0.833333em 0.35em 0.833333em;
|
||||
}
|
||||
.check-box {
|
||||
-fx-background-radius: 0;
|
||||
}
|
||||
|
||||
.choice-box {
|
||||
/* TODO add padding */
|
||||
-fx-background-radius: 0;
|
||||
}
|
||||
/* Dark */
|
||||
.background {
|
||||
-fx-background-color: derive(#1d1d1d,20%);
|
||||
}
|
||||
|
||||
.label {
|
||||
-fx-font-size: 11pt;
|
||||
-fx-font-family: "Segoe UI Semibold";
|
||||
-fx-text-fill: white;
|
||||
-fx-opacity: 0.6;
|
||||
}
|
||||
|
||||
.label-bright {
|
||||
-fx-font-size: 11pt;
|
||||
-fx-font-family: "Segoe UI Semibold";
|
||||
-fx-text-fill: white;
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
|
||||
.label-header {
|
||||
-fx-font-size: 32pt;
|
||||
-fx-font-family: "Segoe UI Light";
|
||||
-fx-text-fill: white;
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
|
||||
.table-view {
|
||||
-fx-base: #1d1d1d;
|
||||
-fx-control-inner-background: #1d1d1d;
|
||||
-fx-background-color: #1d1d1d;
|
||||
-fx-table-cell-border-color: transparent;
|
||||
-fx-table-header-border-color: transparent;
|
||||
-fx-padding: 5;
|
||||
}
|
||||
|
||||
.table-view .column-header-background {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.table-view .column-header, .table-view .filler {
|
||||
-fx-size: 35;
|
||||
-fx-border-width: 0 0 1 0;
|
||||
-fx-background-color: transparent;
|
||||
-fx-border-color:
|
||||
transparent
|
||||
transparent
|
||||
derive(-fx-base, 80%)
|
||||
transparent;
|
||||
-fx-border-insets: 0 10 1 0;
|
||||
}
|
||||
|
||||
.table-view .column-header .label {
|
||||
-fx-font-size: 20pt;
|
||||
-fx-font-family: "Segoe UI Light";
|
||||
-fx-text-fill: white;
|
||||
-fx-alignment: center-left;
|
||||
-fx-opacity: 1;
|
||||
}
|
||||
|
||||
.table-view:focused .table-row-cell:filled:focused:selected {
|
||||
-fx-background-color: -fx-focus-color;
|
||||
}
|
||||
|
||||
.split-pane:horizontal > .split-pane-divider {
|
||||
-fx-border-color: transparent #1d1d1d transparent #1d1d1d;
|
||||
-fx-background-color: transparent, derive(#1d1d1d,20%);
|
||||
}
|
||||
|
||||
.split-pane {
|
||||
-fx-padding: 1 0 0 0;
|
||||
}
|
||||
|
||||
.menu-bar {
|
||||
-fx-background-color: derive(#1d1d1d,20%);
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
-fx-background-color: derive(#1d1d1d,50%);
|
||||
}
|
||||
|
||||
.menu-bar .label {
|
||||
-fx-font-size: 14pt;
|
||||
-fx-font-family: "Segoe UI Light";
|
||||
-fx-text-fill: white;
|
||||
-fx-opacity: 0.9;
|
||||
}
|
||||
|
||||
.menu .left-container {
|
||||
-fx-background-color: black;
|
||||
}
|
||||
|
||||
.text-field {
|
||||
-fx-font-size: 12pt;
|
||||
-fx-font-family: "Segoe UI Semibold";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Metro style Push Button
|
||||
* Author: Pedro Duque Vieira
|
||||
* http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/
|
||||
*/
|
||||
.button {
|
||||
-fx-padding: 5 22 5 22;
|
||||
-fx-border-color: #e2e2e2;
|
||||
-fx-border-width: 2;
|
||||
-fx-background-radius: 0;
|
||||
-fx-background-color: #1d1d1d;
|
||||
-fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
-fx-font-size: 11pt;
|
||||
-fx-text-fill: #d8d8d8;
|
||||
-fx-background-insets: 0 0 0 0, 0, 1, 2;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
-fx-background-color: #3a3a3a;
|
||||
}
|
||||
|
||||
.button:pressed, .button:default:hover:pressed {
|
||||
-fx-background-color: white;
|
||||
-fx-text-fill: #1d1d1d;
|
||||
}
|
||||
|
||||
.button:focused {
|
||||
-fx-border-color: white, white;
|
||||
-fx-border-width: 1, 1;
|
||||
-fx-border-style: solid, segments(1, 1);
|
||||
-fx-border-radius: 0, 0;
|
||||
-fx-border-insets: 1 1 1 1, 0;
|
||||
}
|
||||
|
||||
.button:disabled, .button:default:disabled {
|
||||
-fx-opacity: 0.4;
|
||||
-fx-background-color: #1d1d1d;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
.button:default {
|
||||
-fx-background-color: -fx-focus-color;
|
||||
-fx-text-fill: #ffffff;
|
||||
}
|
||||
|
||||
.button:default:hover {
|
||||
-fx-background-color: derive(-fx-focus-color,30%);
|
||||
}
|
||||
/* Console */
|
||||
.text-area {
|
||||
-fx-font-family: Consolas;
|
||||
-fx-font-size: 15;
|
||||
-fx-text-fill: #63f542;
|
||||
-fx-display-caret:true;
|
||||
}
|
||||
|
||||
.text-area .content {
|
||||
-fx-background-color: #000000;
|
||||
}
|
||||
|
||||
/* tabs */
|
||||
.tab-pane:top *.tab-header-area {
|
||||
-fx-background-insets: 0, 0 0 1 0;
|
||||
/* -fx-padding: 0.416667em 0.166667em 0.0em 0.833em; /* 5 2 0 10 */
|
||||
-fx-padding: 0.416667em 0.166667em 0.0em 0.0em; /* overridden as 5 2 0 0 */
|
||||
}
|
||||
|
||||
.tab-pane .tab-header-area .tab-header-background {
|
||||
-fx-opacity: 0;
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
-fx-tab-min-width:120px;
|
||||
-fx-tab-min-height:50px;
|
||||
-fx-tab-max-height:50px;
|
||||
}
|
||||
|
||||
.tab-pane .tab {
|
||||
-fx-background-color: derive(#1d1d1d,20%);
|
||||
-fx-background-insets: 0 1 0 1,0,0;
|
||||
-fx-label-padding: 0.25em 0.25em 0.25em 0.25em;
|
||||
}
|
||||
|
||||
.tab .tab-label {
|
||||
-fx-font-size: 14pt;
|
||||
-fx-font-family: "Segoe UI Light";
|
||||
-fx-text-fill: white;
|
||||
-fx-opacity: 0.9;
|
||||
-fx-display-caret:true;
|
||||
}
|
||||
|
||||
.tab-pane .tab:selected {
|
||||
-fx-background-color: -fx-focus-color;
|
||||
}
|
||||
|
||||
.algoPane {
|
||||
-fx-background-color: white;
|
||||
}
|
||||
|
||||
.algoPane .label {
|
||||
-fx-text-fill: black;
|
||||
-fx-font-size: 16pt;
|
||||
-fx-font-family: "Segoe UI Light";
|
||||
-fx-opacity: 0.9;
|
||||
}
|
||||
|
||||
.default-color0.chart-series-line { -fx-stroke: transparent; }
|
||||
.default-color1.chart-series-line { -fx-stroke: red; }
|
||||
|
||||
.default-color0.chart-line-symbol {
|
||||
-fx-background-color: white, green;
|
||||
}
|
||||
.default-color1.chart-line-symbol {
|
||||
-fx-background-color: transparent, transparent;
|
||||
}
|
||||
|
||||
.default-color0.chart-legend-item-symbol{
|
||||
-fx-background-color: green;
|
||||
}
|
||||
.default-color1.chart-legend-item-symbol{
|
||||
-fx-background-color: red;
|
||||
}
|
64
src/main/resources/views/AlgorithmTab.fxml
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.chart.LineChart?>
|
||||
<?import javafx.scene.chart.NumberAxis?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.Cursor?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.FlowPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<BorderPane xmlns:fx="http://javafx.com/fxml/1" prefHeight="400.0" prefWidth="600.0"
|
||||
styleClass="algoPane" xmlns="http://javafx.com/javafx/10.0.2-internal"
|
||||
fx:controller="de.wwwu.awolf.view.controller.AlgorithmTabController">
|
||||
<center>
|
||||
<LineChart BorderPane.alignment="CENTER" prefHeight="398.0" prefWidth="390.0" title="Plot"
|
||||
fx:id="chart">
|
||||
<xAxis>
|
||||
<NumberAxis label="X" side="BOTTOM">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
</NumberAxis>
|
||||
</xAxis>
|
||||
<yAxis>
|
||||
<NumberAxis label="Y" side="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</padding>
|
||||
</NumberAxis>
|
||||
</yAxis>
|
||||
</LineChart>
|
||||
</center>
|
||||
<left>
|
||||
<VBox BorderPane.alignment="CENTER" alignment="TOP_CENTER" prefHeight="200.0" prefWidth="200.0"
|
||||
fx:id="vBox">
|
||||
<BorderPane.margin>
|
||||
<Insets left="10.0"/>
|
||||
</BorderPane.margin>
|
||||
<children>
|
||||
</children>
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
<padding>
|
||||
<Insets top="10.0"/>
|
||||
</padding>
|
||||
</VBox>
|
||||
</left>
|
||||
<top>
|
||||
<FlowPane BorderPane.alignment="CENTER" hgap="5.0" prefHeight="25.0" prefWidth="200.0">
|
||||
<BorderPane.margin>
|
||||
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
|
||||
</BorderPane.margin>
|
||||
<children>
|
||||
<Button alignment="CENTER" contentDisplay="CENTER" defaultButton="true" pickOnBounds="false"
|
||||
text="Start" fx:id="startButton">
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
</Button>
|
||||
</children>
|
||||
</FlowPane>
|
||||
</top>
|
||||
</BorderPane>
|
22
src/main/resources/views/MainFrame.fxml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.MenuBar?>
|
||||
<?import javafx.scene.control.TabPane?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<BorderPane xmlns:fx="http://javafx.com/fxml/1" prefHeight="632.0" prefWidth="1118.0"
|
||||
xmlns="http://javafx.com/javafx/10.0.2-internal"
|
||||
fx:controller="de.wwwu.awolf.view.ViewController">
|
||||
<center>
|
||||
<TabPane BorderPane.alignment="CENTER" prefHeight="200.0" prefWidth="200.0"
|
||||
tabClosingPolicy="UNAVAILABLE"
|
||||
fx:id="tabPane">
|
||||
<tabs>
|
||||
</tabs>
|
||||
</TabPane>
|
||||
</center>
|
||||
<left>
|
||||
</left>
|
||||
<top>
|
||||
<MenuBar BorderPane.alignment="CENTER" fx:id="menuBar"/>
|
||||
</top>
|
||||
</BorderPane>
|
@ -0,0 +1,37 @@
|
||||
package de.wwwu.awolf.presenter.algorithms.advanced;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.presenter.algorithms.Algorithm;
|
||||
import de.wwwu.awolf.presenter.algorithms.AlgorithmHandler;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 23.10.2017.
|
||||
*/
|
||||
public class LeastMedianOfSquaresEstimatorTest {
|
||||
|
||||
private LeastMedianOfSquaresEstimator lms;
|
||||
private Set<Line> lines;
|
||||
private Line line;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Double[] x = {18d, 24d, 30d, 34d, 38d};
|
||||
Double[] y = {18d, 26d, 30d, 40d, 70d};
|
||||
|
||||
lines = new HashSet<>();
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
lines.add(new Line(x[i], y[i]));
|
||||
}
|
||||
line = AlgorithmHandler.getInstance().runAlgorithmByType(Algorithm.Type.LMS, lines);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package de.wwwu.awolf.presenter.algorithms.advanced;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 23.10.2017.
|
||||
*/
|
||||
public class TheilSenEstimatorTest {
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Double[] x = {18d, 24d, 30d, 34d, 38d};
|
||||
Double[] y = {18d, 26d, 30d, 40d, 70d};
|
||||
|
||||
List<Line> lines = new LinkedList<>();
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
lines.add(new Line(x[i], y[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package de.wwwu.awolf.presenter.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 23.10.2017.
|
||||
*/
|
||||
public class FastElementSelectorTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void randomizedSelect() throws Exception {
|
||||
Double[] array = {1d, 2d, 3d, 4d};
|
||||
ArrayList<Double> list = new ArrayList<>(Arrays.asList(array));
|
||||
assertEquals(FastElementSelector.randomizedSelect(list, 0), 1d, 0.00001);
|
||||
assertEquals(FastElementSelector.randomizedSelect(list, 2), 2d, 0.00001);
|
||||
}
|
||||
|
||||
@Test(expected = IndexOutOfBoundsException.class)
|
||||
public void testIndexOutOfBoundsException() {
|
||||
FastElementSelector.randomizedSelect(Collections.emptyList(), 42);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package de.wwwu.awolf.presenter.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import de.wwwu.awolf.model.Line;
|
||||
import de.wwwu.awolf.model.LineModel;
|
||||
import java.util.ArrayList;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden.
|
||||
*
|
||||
* @Author: Armin Wolf
|
||||
* @Email: a_wolf28@uni-muenster.de
|
||||
* @Date: 23.10.2017.
|
||||
*/
|
||||
public class IntersectionCounterTest {
|
||||
|
||||
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));
|
||||
for (Line l : lineModel.getLines()) {
|
||||
System.out.println("Steigung: " + l.getM() + "\t y-Achsenabschnitt: " + l.getB());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run() throws Exception {
|
||||
IntersectionComputer instance = IntersectionComputer.getInstance();
|
||||
assertEquals(3, IntersectionComputer.getInstance()
|
||||
.compute(new ArrayList<>(lineModel.getLines()), -9999, 9999).size());
|
||||
}
|
||||
|
||||
}
|