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
21 public static double DELTA = 0.000005;
22
23 private SortedSet dataPoints = new TreeSet();
24
25 private int count = 0;
26 private double total = 0.0;
27
28 public void addDataPoint(DataPoint point) {
29 count++;
30 total += point.getScore();
31 dataPoints.add(point);
32 }
33
34 public void apply(List acus, RuleContext ctx) {
35 visitAll(acus, ctx);
36
37 double deviation;
38 double minimum = 0.0;
39
40 if (hasProperty("sigma")) {
41 deviation = getStdDev();
42 double sigma = getDoubleProperty("sigma");
43 minimum = getMean() + (sigma * deviation);
44 }
45
46 if (hasProperty("minimum")) {
47 double mMin = getDoubleProperty("minimum");
48 if (mMin > minimum) {
49 minimum = mMin;
50 }
51 }
52
53 SortedSet newPoints = applyMinimumValue(dataPoints, minimum);
54
55 if (hasProperty("topscore")) {
56 int topScore = getIntProperty("topscore");
57 if (newPoints.size() >= topScore) {
58 newPoints = applyTopScore(newPoints, topScore);
59 }
60 }
61
62 makeViolations(ctx, newPoints);
63
64 double low = 0.0d;
65 double high = 0.0d;
66 if (!dataPoints.isEmpty()) {
67 low = ((DataPoint) dataPoints.first()).getScore();
68 high = ((DataPoint) dataPoints.last()).getScore();
69 }
70
71 ctx.getReport().addMetric(new Metric(this.getName(), count, total, low, high, getMean(), getStdDev()));
72
73 dataPoints.clear();
74 }
75
76 protected double getMean() {
77 return total / count;
78 }
79
80 protected double getStdDev() {
81 Iterator points = dataPoints.iterator();
82 double mean = getMean();
83 double deltaSq = 0.0;
84
85 if (dataPoints.size() < 2) {
86 return Double.NaN;
87 }
88
89 while (points.hasNext()) {
90 DataPoint point = (DataPoint) points.next();
91 deltaSq += ((point.getScore() - mean) * (point.getScore() - mean));
92 }
93
94 return Math.sqrt(deltaSq / (dataPoints.size() - 1));
95 }
96
97 protected SortedSet applyMinimumValue(SortedSet pointSet, double minValue) {
98 Iterator points = pointSet.iterator();
99 SortedSet RC = new TreeSet();
100
101 while (points.hasNext()) {
102 DataPoint point = (DataPoint) points.next();
103
104 if (point.getScore() > (minValue - DELTA)) {
105 RC.add(point);
106 }
107 }
108 return RC;
109 }
110
111 protected SortedSet applyTopScore(SortedSet points, int topScore) {
112 SortedSet s = new TreeSet();
113 Object[] arr = points.toArray();
114 for (int i=arr.length-1; i>=(arr.length - topScore); i--) {
115 s.add(arr[i]);
116 }
117 return s;
118 }
119
120 protected void makeViolations(RuleContext ctx, Set p) {
121 Iterator points = p.iterator();
122 while (points.hasNext()) {
123 DataPoint point = (DataPoint) points.next();
124 ctx.getReport().addRuleViolation(createRuleViolation(ctx, point.getLineNumber(), point.getMessage()));
125 }
126 }
127 }