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 ;
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 ;
/ * *
* 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 ;
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 ;
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-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-04-06 11:07:10 +00:00
int n = this . setOfLines . size ( ) ;
2020-04-05 19:11:50 +00:00
this . N = BinomialCoeffizient . run ( n , 2 ) ;
//this.k = Integer.valueOf((int) (N * 0.5)) - 1;
this . k = ( int ) ( N / 2 ) ;
2020-04-06 11:07:10 +00:00
double POSITIV_INF = 9999 . 0 ;
double NEGATIV_INF = - 9999 . 0 ;
2020-04-05 19:11:50 +00:00
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 ) {
2020-04-06 11:07:10 +00:00
double EPSILON = 0 . 00001 ;
2020-04-05 19:11:50 +00:00
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
2020-04-06 11:07:10 +00:00
//Hilfsvariablen (siehe original Paper)
double j = ( r / N ) * ( double ) ( k - numberOfIntersections ) ;
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 * /
do {
//zufällige Stichprobe
List < Point > sampledIntersections = RandomSampler
. run ( intervalIntersections , r ) ;
aVariant = FastElementSelector
. randomizedSelect ( getIntersectionAbscissas ( sampledIntersections ) ,
jA ) ;
bVariant = FastElementSelector
. randomizedSelect ( getIntersectionAbscissas ( sampledIntersections ) ,
jB ) ;
2020-04-06 11:07:10 +00:00
} while ( ! checkCondition ( NEGATIV_INF ) ) ;
2020-04-05 19:11:50 +00:00
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 ) {
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-04-06 11:07:10 +00:00
private Boolean checkCondition ( final double lowerBound ) {
2020-04-05 19:11:50 +00:00
//Double kthElement = FastElementSelector.randomizedSelect(xCoordinates, k);
//Boolean cond1 = (kthElement > aVariant) && (kthElement <= bVariant);
2020-04-06 11:07:10 +00:00
int lowerCount = getIntervalSize ( lowerBound , aVariant ) ;
int higherCount = getIntervalSize ( lowerBound , bVariant ) ;
2020-04-05 19:11:50 +00:00
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 ( ) ) ;
}
2020-04-06 11:07:10 +00:00
//TODO
double pseudoIndex = getIntervalSize ( - 9999 . 0 , interval . getLower ( ) ) * 1 . 0 ;
2020-04-05 19:11:50 +00:00
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 ) {
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 ) ;
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
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
}