001/*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019 */
020package org.sonar.plugins.core.timemachine;
021
022import java.util.List;
023
024public class TendencyAnalyser {
025
026  public static final Integer TENDENCY_BIG_UP = 2;
027  public static final Integer TENDENCY_UP = 1;
028  public static final Integer TENDENCY_NEUTRAL = 0;
029  public static final Integer TENDENCY_DOWN = -1;
030  public static final Integer TENDENCY_BIG_DOWN = -2;
031
032  public Integer analyseLevel(List<Double> values) {
033    TendencyAnalyser.SlopeData slopeData = analyse(values);
034    if (slopeData != null) {
035      return slopeData.getLevel();
036    }
037    return null;
038  }
039
040  public SlopeData analyse(List<Double> values) {
041    double sumY = 0.0;
042    double sumX = 0.0;
043    double sumYPower2 = 0.0;
044    double sumXY = 0.0;
045    double sumXPower2 = 0.0;
046    int nbrPoints = 0;
047    boolean nullValuesYList = true;
048    int i = 0;
049    for (Double p : values) {
050      if (p != null) {
051        nullValuesYList = false;
052        //SumY calculation
053        sumY += p;
054        // sumYPower2 calculation
055        sumYPower2 += p * p;
056        //sumXY calculation
057        sumXY += p * (i + 1);
058        //SumX calculation
059        sumX += (i + 1);
060        //sumXPower2 calculation
061        sumXPower2 += (i + 1) * (i + 1);
062        //Point number calculation
063        nbrPoints++;
064      }
065      i++;
066    }
067    // no tendency if null values or only 1 value
068    if (nullValuesYList || nbrPoints == 1) {
069      return null;
070    }
071    double n0 = (((nbrPoints) * (sumXY)) - ((sumX) * (sumY)));
072    double d = (((nbrPoints) * (sumXPower2)) - ((sumX) * (sumX)));
073    double n1 = (((sumY) * (sumXPower2)) - ((sumX) * (sumXY)));
074
075    SlopeData result = new SlopeData();
076
077    //yIntercept Calculation the value when X equals zero
078    result.setYIntercept(n1 / d);
079    // Slope Calculation
080    if (n0 == 0d && d == 0d) {
081      result.setSlope(0.0);
082    } else {
083      Double slope = n0 / d;
084      if (Double.isNaN(slope) || Double.isInfinite(slope)) {
085        result.setSlope(null);
086      } else {
087        result.setSlope(slope);
088      }
089    }
090    result.setSumXPower2(sumXPower2);
091    result.setSumXY(sumXY);
092    result.setSumYPower2(sumYPower2);
093
094    if (sumXPower2 == 0 || sumYPower2 == 0) {
095      result.setCorrelationRate(0.0);
096    } else {
097      result.setCorrelationRate((sumXY) / (Math.sqrt(sumXPower2 * sumYPower2)));
098    }
099
100    return result;
101  }
102
103
104  static class SlopeData {
105    private double sumXPower2;
106    private double sumYPower2;
107    private double sumXY;
108    private double yIntercept; // not used today
109    private Double slope;
110    private Double correlationRate;
111
112    public double getSumXPower2() {
113      return sumXPower2;
114    }
115
116    public void setSumXPower2(double sumXPower2) {
117      this.sumXPower2 = sumXPower2;
118    }
119
120    public double getSumYPower2() {
121      return sumYPower2;
122    }
123
124    public void setSumYPower2(double sumYPower2) {
125      this.sumYPower2 = sumYPower2;
126    }
127
128    public double getSumXY() {
129      return sumXY;
130    }
131
132    public void setSumXY(double sumXY) {
133      this.sumXY = sumXY;
134    }
135
136    public double getYIntercept() {
137      return yIntercept;
138    }
139
140    public void setYIntercept(double yIntercept) {
141      this.yIntercept = yIntercept;
142    }
143
144    public Double getSlope() {
145      return slope;
146    }
147
148    public void setSlope(Double slope) {
149      this.slope = slope;
150    }
151
152    public Double getCorrelationRate() {
153      return correlationRate;
154    }
155
156    public void setCorrelationRate(Double correlationRate) {
157      this.correlationRate = correlationRate;
158    }
159
160    public Integer getLevel() {
161      double hSlope = 0.8;
162      double nSlope = 0.2;
163
164      double vHighCorcoef = 1.0;
165      double modCorcoef = 0.69;
166      Double correlationCoeff = getCorrelationRate();
167      boolean vHCorCoefPos = (correlationCoeff > modCorcoef) && (correlationCoeff <= vHighCorcoef);
168      boolean vHCorCoefNeg = (correlationCoeff < -modCorcoef) && (correlationCoeff >= -vHighCorcoef);
169
170      if ((vHCorCoefPos || vHCorCoefNeg) && (slope >= hSlope)) {
171        return TENDENCY_BIG_UP;
172
173      } else if ((vHCorCoefPos || vHCorCoefNeg) && (slope <= -hSlope)) {
174        return TENDENCY_BIG_DOWN;
175
176      } else if ((vHCorCoefPos || vHCorCoefNeg) && ((slope >= nSlope) && (slope < hSlope))) {
177        return TENDENCY_UP;
178
179      } else if ((vHCorCoefPos || vHCorCoefNeg) && ((slope <= -nSlope) && (slope > -hSlope))) {
180        return TENDENCY_DOWN;
181
182      } else if ((vHCorCoefPos || vHCorCoefNeg) && ((slope < nSlope) || (slope > -nSlope))) {
183        return TENDENCY_NEUTRAL;
184
185      } else if (correlationCoeff == 0 && slope == 0 && !vHCorCoefPos && !vHCorCoefNeg) {
186        return TENDENCY_NEUTRAL;
187      }
188      return null;
189    }
190  }
191}