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 */
020 package org.sonar.plugins.core.timemachine;
021
022 import java.util.List;
023
024 public 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 }