2020-03-21 00:37:09 +00:00
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 ;
2020-03-28 15:24:35 +00:00
import de.wwwu.awolf.presenter.AbstractPresenter ;
2020-03-21 00:37:09 +00:00
import de.wwwu.awolf.presenter.algorithms.Algorithm ;
2020-03-28 15:24:35 +00:00
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 ;
2020-04-05 18:53:52 +00:00
import java.util.ArrayList ;
import java.util.Collection ;
import java.util.LinkedHashSet ;
import java.util.LinkedList ;
import java.util.List ;
import java.util.Set ;
2020-03-21 00:37:09 +00:00
import java.util.concurrent.Flow ;
2017-06-26 14:01:54 +00:00
2017-05-28 12:00:01 +00:00
/ * *
* Implementierung verschiedener Algorithmen zur Berechnung von Ausgleichsgeraden .
*
* @Author : Armin Wolf
* @Email : a_wolf28 @uni - muenster . de
* @Date : 28 . 05 . 2017 .
* /
2020-03-28 15:24:35 +00:00
public class TheilSenEstimator implements Algorithm {
private static final Algorithm . Type type = Type . TS ;
2017-06-26 14:01:54 +00:00
2020-03-24 07:04:07 +00:00
private final double POSITIV_INF = 9999 . 0 ;
private final double NEGATIV_INF = - 9999 . 0 ;
2019-08-01 05:19:04 +00:00
private final double EPSILON = 0 . 00001 ;
2020-03-21 00:37:09 +00:00
private List < Line > setOfLines ;
2017-06-29 15:32:54 +00:00
//Hilfsvariablen (siehe original Paper)
2019-08-01 05:19:04 +00:00
private double j ;
private int jA ;
private int jB ;
private double r ;
private int n ;
private double N ;
private int k ;
2017-06-29 15:32:54 +00:00
//Intervall und die temporaeren Grenzen
private Interval interval ;
2019-08-01 05:19:04 +00:00
private double aVariant ;
private double bVariant ;
private double slope ;
private double yInterception ;
2020-03-21 00:37:09 +00:00
private Flow . Subscriber < ? super AlgorithmData > subscriber ;
2020-03-28 15:24:35 +00:00
private AbstractPresenter presenter ;
2017-08-01 19:59:33 +00:00
2017-06-29 15:32:54 +00:00
/ * *
2020-04-05 18:53:52 +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
2017-06-29 15:32:54 +00:00
* /
2020-03-21 19:54:03 +00:00
public Line call ( ) {
2020-03-28 15:24:35 +00:00
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 ) ;
2017-06-29 15:32:54 +00:00
//damit eine initiale Ordnung herscht
2017-06-30 08:34:01 +00:00
//Collections.sort(intervalIntersections);
2017-06-29 15:32:54 +00:00
2020-03-20 17:08:18 +00:00
r = n ;
2020-04-05 18:53:52 +00:00
List < Point > intervalIntersections = new LinkedList < > ( IntersectionComputer . getInstance ( )
. compute ( setOfLines , interval . getLower ( ) , interval . getUpper ( ) ) ) ;
2017-06-29 15:32:54 +00:00
while ( true ) {
2020-04-05 18:53:52 +00:00
if ( this . N < = n
| | ( Math . abs ( interval . getUpper ( ) - interval . getLower ( ) ) ) < EPSILON ) {
2017-06-29 15:32:54 +00:00
break ;
} else {
//Anzahl der Schnittpunkte im Intervall [-Inf, a)
2020-04-05 18:53:52 +00:00
int numberOfIntersections = getIntervalSize ( NEGATIV_INF ,
interval . getLower ( ) ) ;
2017-06-29 15:32:54 +00:00
//Randomized Interpolating Search
j = ( r / N ) * ( double ) ( k - numberOfIntersections ) ;
2017-09-09 17:41:32 +00:00
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 ) ) ) ) ;
2017-06-29 15:32:54 +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
2020-04-05 18:53:52 +00:00
List < Point > sampledIntersections = RandomSampler
. run ( intervalIntersections , r ) ;
aVariant = FastElementSelector
. randomizedSelect ( getIntersectionAbscissas ( sampledIntersections ) ,
jA ) ;
bVariant = FastElementSelector
. randomizedSelect ( getIntersectionAbscissas ( sampledIntersections ) ,
jB ) ;
2017-06-29 15:32:54 +00:00
} while ( ! checkCondition ( ) ) ;
interval . setLower ( aVariant ) ;
interval . setUpper ( bVariant ) ;
2020-04-05 18:53:52 +00:00
intervalIntersections = getOpenIntervalElements ( interval . getLower ( ) ,
interval . getUpper ( ) ) ;
2020-03-24 07:04:07 +00:00
N = getIntervalSize ( interval . getLower ( ) , interval . getUpper ( ) ) ;
2017-06-29 15:32:54 +00:00
}
}
2019-08-01 05:19:04 +00:00
2020-03-21 19:54:03 +00:00
return pepareResult ( ) ;
2017-06-29 15:32:54 +00:00
}
2020-03-28 15:24:35 +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 ) {
this . presenter = presenter ;
subscribe ( presenter ) ;
}
2020-03-23 06:58:40 +00:00
private List < Double > getIntersectionAbscissas ( List < Point > interections ) {
List < Double > abscissas = new ArrayList < > ( ) ;
interections . forEach ( e - > abscissas . add ( e . getX ( ) ) ) ;
return abscissas ;
}
2017-06-29 15:32:54 +00:00
/ * *
2020-04-05 18:53:52 +00:00
* 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 .
2017-06-29 15:32:54 +00:00
*
* @return Boolscher Wert ob die Bedingung erfüllt ist
* /
private Boolean checkCondition ( ) {
2017-08-03 06:27:38 +00:00
//Double kthElement = FastElementSelector.randomizedSelect(xCoordinates, k);
//Boolean cond1 = (kthElement > aVariant) && (kthElement <= bVariant);
2017-09-07 09:21:48 +00:00
2017-09-23 12:13:09 +00:00
int lowerCount = getIntervalSize ( NEGATIV_INF , aVariant ) ;
int higherCount = getIntervalSize ( NEGATIV_INF , bVariant ) ;
2017-09-07 09:21:48 +00:00
Boolean conda = k > lowerCount ;
Boolean condb = k < = higherCount ;
2017-08-03 06:27:38 +00:00
Boolean cond1 = conda & & condb ;
2017-09-10 15:45:47 +00:00
Boolean cond2 = ( higherCount - lowerCount ) < = ( ( 11 * N ) / Math . sqrt ( r ) ) ;
2017-06-29 21:22:34 +00:00
2017-09-10 15:45:47 +00:00
return ( cond1 & & cond2 ) | | ( aVariant = = bVariant ) ;
2017-06-29 15:32:54 +00:00
}
/ * *
2020-04-05 18:53:52 +00:00
* Berechne wieviele von den Schnittpunkten in dem Interval zwischen < code > a < / code > und
* < code > b < / code > enthalten sind .
2017-06-29 15:32:54 +00:00
*
* @param a untere Grenze des Intervals
* @param b obere Grenze des Intrvals
* @return Anzahl der Schnittpunkte im Interval [ a , b )
* /
2017-09-23 12:13:09 +00:00
public int getIntervalSize ( double a , double b ) {
2020-03-28 15:24:35 +00:00
return getOpenIntervalElements ( a , b ) . size ( ) ;
2017-06-26 14:01:54 +00:00
}
2017-06-29 15:32:54 +00:00
/ * *
2020-04-05 18:53:52 +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 .
2017-06-29 15:32:54 +00:00
*
* @param a untere Grenze des Intervals
* @param b obere Grenze des Intrvals
2017-09-07 09:21:48 +00:00
* @return Liste der Schnittpunkte die im Interval ( a , b ) vertreten sind
2017-06-29 15:32:54 +00:00
* /
2020-03-21 00:37:09 +00:00
public List < Point > getOpenIntervalElements ( double a , double b ) {
2020-04-05 18:53:52 +00:00
Collection < Point > intersections = IntersectionComputer . getInstance ( )
. compute ( setOfLines , a , b ) ;
2020-03-24 07:04:07 +00:00
return new ArrayList < > ( intersections ) ;
2017-06-27 08:08:32 +00:00
}
2020-03-21 19:54:03 +00:00
private Line pepareResult ( ) {
2017-08-02 05:40:08 +00:00
double m , x ;
double b , y ;
2020-04-05 18:53:52 +00:00
List < Point > resultSt = getOpenIntervalElements ( interval . getLower ( ) ,
interval . getUpper ( ) ) ;
2020-03-21 00:37:09 +00:00
List < Double > resultAbscissas = new ArrayList < > ( ) ;
2017-09-09 17:41:32 +00:00
2017-09-10 15:45:47 +00:00
for ( Point p : resultSt ) {
2017-09-09 17:41:32 +00:00
resultAbscissas . add ( p . getX ( ) ) ;
2017-08-02 05:40:08 +00:00
}
2017-06-29 15:32:54 +00:00
2020-03-23 06:58:40 +00:00
List < Double > yCoords = new ArrayList < > ( ) ;
2020-03-24 07:04:07 +00:00
for ( Point p : getOpenIntervalElements ( interval . getLower ( ) , interval . getUpper ( ) ) ) {
2020-03-23 06:58:40 +00:00
yCoords . add ( p . getY ( ) ) ;
2017-08-02 05:40:08 +00:00
}
2017-06-29 15:32:54 +00:00
2020-03-24 07:04:07 +00:00
double pseudoIndex = getIntervalSize ( NEGATIV_INF , interval . getLower ( ) ) * 1 . 0 ;
2017-09-10 15:45:47 +00:00
m = FastElementSelector . randomizedSelect ( resultAbscissas , k - pseudoIndex ) ;
2017-06-29 15:32:54 +00:00
2020-03-23 06:58:40 +00:00
Set < Double > unique = new LinkedHashSet < > ( yCoords ) ;
yCoords . clear ( ) ;
yCoords . addAll ( unique ) ;
b = FastElementSelector . randomizedSelect ( yCoords , yCoords . size ( ) * 0 . 5 ) * - 1 ;
2017-08-02 05:40:08 +00:00
slope = m ;
yInterception = b ;
2017-06-29 15:32:54 +00:00
2020-03-21 00:37:09 +00:00
if ( this . subscriber ! = null ) {
AlgorithmData data = new AlgorithmData ( ) ;
2020-04-05 17:28:38 +00:00
data . setAlgorithmType ( getType ( ) ) ;
data . setType ( SubscriberType . ALGORITHM ) ;
2020-03-21 00:37:09 +00:00
data . setLineData ( new Line ( m , b ) ) ;
this . subscriber . onNext ( data ) ;
2017-06-29 15:32:54 +00:00
}
2020-03-21 19:54:03 +00:00
return new Line ( getSlope ( ) , getYInterception ( ) ) ;
2017-06-29 11:10:15 +00:00
}
2017-06-29 15:32:54 +00:00
2017-10-15 13:21:53 +00:00
/ * *
* @return Steigung
* /
2017-08-01 19:59:33 +00:00
public Double getSlope ( ) {
return slope ;
}
2017-10-15 13:21:53 +00:00
/ * *
* @return y - Achsenabschnitt
* /
2020-03-21 19:54:03 +00:00
public Double getYInterception ( ) {
2017-08-01 19:59:33 +00:00
return yInterception ;
}
2020-03-21 00:37:09 +00:00
@Override
public void subscribe ( Flow . Subscriber < ? super Data > subscriber ) {
this . subscriber = subscriber ;
}
2017-05-28 12:00:01 +00:00
}