1 /***
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.stat;
5
6 import net.sourceforge.pmd.AbstractRule;
7 import net.sourceforge.pmd.RuleContext;
8
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.Set;
12 import java.util.SortedSet;
13 import java.util.TreeSet;
14
15 /***
16 * @author David Dixon-Peugh
17 * Aug 8, 2002 StatisticalRule.java
18 */
19 public abstract class StatisticalRule extends AbstractRule {
20 public static double DELTA = 0.000005;
21
22 private SortedSet dataPoints = new TreeSet();
23
24 private int count = 0;
25 private double total = 0.0;
26 private double totalSquared = 0.0;
27
28 public void addDataPoint(DataPoint point) {
29 count++;
30 total += point.getScore();
31 totalSquared += point.getScore() * point.getScore();
32 dataPoints.add(point);
33 }
34
35 public void apply(List acus, RuleContext ctx) {
36 visitAll(acus, ctx);
37
38 double deviation;
39 double minimum = 0.0;
40
41 if (hasProperty("sigma")) {
42 deviation = getStdDev();
43 double sigma = getDoubleProperty("sigma");
44
45 minimum = getMean() + (sigma * deviation);
46 }
47
48 if (hasProperty("minimum")) {
49 double mMin = getDoubleProperty("minimum");
50 if (mMin > minimum) {
51 minimum = mMin;
52 }
53 }
54
55 SortedSet newPoints = applyMinimumValue(dataPoints, minimum);
56
57 if (hasProperty("topscore")) {
58 int topScore = getIntProperty("topscore");
59 if (newPoints.size() >= topScore) {
60 newPoints = applyTopScore(newPoints, topScore);
61 }
62 }
63
64 makeViolations(ctx, newPoints);
65
66 double low = 0.0d;
67 double high = 0.0d;
68 if (!dataPoints.isEmpty()) {
69 low = ((DataPoint) dataPoints.first()).getScore();
70 high = ((DataPoint) dataPoints.last()).getScore();
71 }
72
73 ctx.getReport().addMetric(new Metric(this.getName(), count, total, low, high, getMean(), getStdDev()));
74
75 dataPoints.clear();
76 }
77
78 protected double getMean() {
79 return total / count;
80 }
81
82 protected double getStdDev() {
83 Iterator points = dataPoints.iterator();
84 double mean = getMean();
85 double deltaSq = 0.0;
86
87 if (dataPoints.size() < 2) {
88 return Double.NaN;
89 }
90
91 while (points.hasNext()) {
92 DataPoint point = (DataPoint) points.next();
93 deltaSq += ((point.getScore() - mean) * (point.getScore() - mean));
94 }
95
96 return Math.sqrt( deltaSq / (dataPoints.size() - 1));
97 }
98
99 protected SortedSet applyMinimumValue(SortedSet pointSet, double minValue) {
100 Iterator points = pointSet.iterator();
101 SortedSet RC = new TreeSet();
102
103 while (points.hasNext()) {
104 DataPoint point = (DataPoint) points.next();
105
106 if (point.getScore() > (minValue - DELTA)) {
107 RC.add(point);
108 }
109 }
110 return RC;
111 }
112
113 protected SortedSet applyTopScore(SortedSet points, int topScore) {
114 SortedSet RC = new TreeSet();
115 for (int i = 0; i < topScore; i++) {
116 DataPoint point = (DataPoint) points.last();
117 points.remove(point);
118
119 RC.add(point);
120 }
121
122 return RC;
123 }
124
125 protected void makeViolations(RuleContext ctx, Set dataPoints) {
126 Iterator points = dataPoints.iterator();
127 while (points.hasNext()) {
128 DataPoint point = (DataPoint) points.next();
129 ctx.getReport().addRuleViolation(this.createRuleViolation(ctx, point.getLineNumber(), point.getMessage()));
130 }
131 }
132 }