2020-04-05 19:11:50 +00:00
package de.wwwu.awolf.presenter.algorithms.advanced ;
2020-04-05 20:27:56 +00:00
import de.wwwu.awolf.model.dao.Interval ;
import de.wwwu.awolf.model.dao.Line ;
import de.wwwu.awolf.model.dao.Point ;
import de.wwwu.awolf.model.communication.AlgorithmMessage ;
import de.wwwu.awolf.model.communication.Message ;
2020-04-05 19:11:50 +00:00
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 ;
2020-05-02 13:07:02 +00:00
import java.util.Collections ;
2020-04-05 19:11:50 +00:00
import java.util.LinkedHashSet ;
import java.util.LinkedList ;
import java.util.List ;
2020-04-05 20:27:56 +00:00
import java.util.Map ;
2020-04-05 19:11:50 +00:00
import java.util.Set ;
import java.util.concurrent.Flow ;
2020-05-02 13:07:02 +00:00
import java.util.stream.Collectors ;
2020-04-05 19:11:50 +00:00
/ * *
* 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 List < Line > setOfLines ;
private double r ;
2020-05-02 13:07:02 +00:00
private double intervalSize ;
2020-04-05 19:11:50 +00:00
private int k ;
//Intervall und die temporaeren Grenzen
private Interval interval ;
private double aVariant ;
private double bVariant ;
private double slope ;
private double yInterception ;
2020-04-05 20:27:56 +00:00
private Flow . Subscriber < ? super AlgorithmMessage > subscriber ;
2020-04-06 11:07:10 +00:00
private Map < String , String > parameter ;
2020-05-02 13:07:02 +00:00
private List < Point > intersections ;
2020-04-05 19:11:50 +00:00
/ * *
* 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 ( ) {
2020-05-02 13:07:02 +00:00
int numberOfLines = this . setOfLines . size ( ) ;
this . intervalSize = BinomialCoeffizient . run ( numberOfLines , 2 ) ;
2020-04-05 19:11:50 +00:00
//this.k = Integer.valueOf((int) (N * 0.5)) - 1;
2020-05-02 13:07:02 +00:00
this . k = ( int ) ( intervalSize / 2 ) ;
2020-04-05 19:11:50 +00:00
2020-05-02 13:07:02 +00:00
interval = new Interval ( Double . MIN_VALUE , Double . MAX_VALUE ) ;
2020-04-05 19:11:50 +00:00
//damit eine initiale Ordnung herscht
2020-05-02 13:07:02 +00:00
r = numberOfLines ;
intersections = new LinkedList < > ( IntersectionComputer . getInstance ( ) . compute ( setOfLines ) ) ;
2020-04-05 19:11:50 +00:00
while ( true ) {
2020-04-06 11:07:10 +00:00
double EPSILON = 0 . 00001 ;
2020-05-02 13:07:02 +00:00
if ( this . intervalSize < = numberOfLines | | ( Math . abs ( interval . getUpper ( ) - interval . getLower ( ) ) ) < EPSILON ) {
2020-04-05 19:11:50 +00:00
break ;
} else {
//Anzahl der Schnittpunkte im Intervall [-Inf, a)
2020-05-02 13:07:02 +00:00
int numberOfIntersections = getIntervalSize ( Double . MIN_VALUE , interval . getLower ( ) ) ;
2020-04-05 19:11:50 +00:00
//Randomized Interpolating Search
2020-04-06 11:07:10 +00:00
//Hilfsvariablen (siehe original Paper)
2020-05-02 13:07:02 +00:00
double j = ( r / intervalSize ) * ( double ) ( k - numberOfIntersections ) ;
2020-04-06 11:07:10 +00:00
int jA = ( int ) Math . max ( 1 , Math . floor ( j - ( 1 . 5 * Math . sqrt ( r ) ) ) ) ;
int jB = ( int ) Math . min ( r , Math . floor ( j + ( 1 . 5 * Math . sqrt ( r ) ) ) ) ;
2020-04-05 19:11:50 +00:00
/ * 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 * /
2020-05-02 13:07:02 +00:00
List < Point > sampledIntersections = new LinkedList < > ( ) ;
2020-04-05 19:11:50 +00:00
do {
//zufällige Stichprobe
2020-05-02 13:07:02 +00:00
Collections . shuffle ( intersections ) ;
for ( int i = 0 ; i < r ; i + + ) {
sampledIntersections . add ( intersections . get ( i % intersections . size ( ) ) ) ;
}
2020-04-05 19:11:50 +00:00
2020-05-02 13:07:02 +00:00
aVariant = FastElementSelector . randomizedSelect ( getIntersectionAbscissas ( sampledIntersections ) , jA ) ;
bVariant = FastElementSelector . randomizedSelect ( getIntersectionAbscissas ( sampledIntersections ) , jB ) ;
} while ( ! checkCondition ( sampledIntersections ) ) ;
2020-04-05 19:11:50 +00:00
interval . setLower ( aVariant ) ;
interval . setUpper ( bVariant ) ;
2020-05-02 13:07:02 +00:00
intersections = getOpenIntervalElements ( interval . getLower ( ) , interval . getUpper ( ) ) ;
intervalSize = getIntervalSize ( interval . getLower ( ) , interval . getUpper ( ) ) ;
2020-04-05 19:11:50 +00:00
}
}
2020-05-02 13:07:02 +00:00
return prepareResults ( ) ;
2020-04-05 19:11:50 +00:00
}
@Override
public void setInput ( Set < Line > lines ) {
this . setOfLines = new LinkedList < > ( lines ) ;
}
@Override
public Type getType ( ) {
return type ;
}
@Override
public void setPresenter ( AbstractPresenter 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
* /
2020-05-02 13:07:02 +00:00
private Boolean checkCondition ( List < Point > sampledIntersections ) {
Point kthElement = FastElementSelector . randomizedSelect ( sampledIntersections , k ) ;
Boolean cond1 = ( kthElement . getX ( ) > aVariant ) & & ( kthElement . getX ( ) < = bVariant ) ;
2020-04-05 19:11:50 +00:00
2020-05-02 13:07:02 +00:00
int count = getIntervalSize ( aVariant , bVariant ) ;
2020-04-05 19:11:50 +00:00
2020-05-02 13:07:02 +00:00
Boolean cond2 = count < = ( ( 11 * intervalSize ) / Math . sqrt ( r ) ) ;
2020-04-05 19:11:50 +00:00
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 ) {
2020-05-02 13:07:02 +00:00
if ( a = = b )
return 0 ;
else
return getOpenIntervalElements ( a , b ) . size ( ) ;
2020-04-05 19:11:50 +00:00
}
/ * *
* 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 ) {
2020-05-02 13:07:02 +00:00
return intersections . stream ( ) . filter ( point - > point . getX ( ) . compareTo ( a ) > = 0 & & point . getX ( ) < 0 ) . collect ( Collectors . toList ( ) ) ;
2020-04-05 19:11:50 +00:00
}
2020-05-02 13:07:02 +00:00
private Line prepareResults ( ) {
List < Point > intervalElements = getOpenIntervalElements ( interval . getLower ( ) , interval . getUpper ( ) ) ;
2020-04-06 11:07:10 +00:00
double pseudoIndex = getIntervalSize ( - 9999 . 0 , interval . getLower ( ) ) * 1 . 0 ;
2020-05-02 13:07:02 +00:00
double m = FastElementSelector . randomizedSelect ( intervalElements , k - pseudoIndex ) . getX ( ) ;
double b = FastElementSelector . randomizedSelect ( intervalElements , intervalElements . size ( ) * 0 . 5 ) . getY ( ) * - 1 ;
slope = m * - 1 ;
2020-04-05 19:11:50 +00:00
yInterception = b ;
if ( this . subscriber ! = null ) {
2020-04-05 20:27:56 +00:00
AlgorithmMessage data = new AlgorithmMessage ( ) ;
2020-04-05 19:11:50 +00:00
data . setAlgorithmType ( getType ( ) ) ;
data . setType ( SubscriberType . ALGORITHM ) ;
2020-05-02 13:07:02 +00:00
data . setLineData ( new Line ( slope , yInterception ) ) ;
2020-04-05 19:11:50 +00:00
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
2020-04-05 20:27:56 +00:00
public void subscribe ( Flow . Subscriber < ? super Message > subscriber ) {
2020-04-05 19:11:50 +00:00
this . subscriber = subscriber ;
}
2020-04-05 20:27:56 +00:00
@Override
2020-04-06 11:07:10 +00:00
public Map < String , String > getParameter ( ) {
2020-04-05 20:27:56 +00:00
return this . parameter ;
}
@Override
2020-04-06 11:07:10 +00:00
public void setParameter ( Map < String , String > parameter ) {
2020-04-05 20:27:56 +00:00
this . parameter = parameter ;
}
2020-04-05 19:11:50 +00:00
}