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 java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10 import java.util.SortedSet;
11 import java.util.TreeSet;
12
13 import net.sourceforge.pmd.AbstractRule;
14 import net.sourceforge.pmd.PropertyDescriptor;
15 import net.sourceforge.pmd.RuleContext;
16 import net.sourceforge.pmd.properties.DoubleProperty;
17 import net.sourceforge.pmd.properties.IntegerProperty;
18
19 /***
20 * @author David Dixon-Peugh
21 * Aug 8, 2002 StatisticalRule.java
22 */
23 public abstract class StatisticalRule extends AbstractRule {
24
25 public static double DELTA = 0.000005;
26
27 private SortedSet dataPoints = new TreeSet();
28
29 private int count = 0;
30 private double total = 0.0;
31
32 private static final PropertyDescriptor sigmaDescriptor = new DoubleProperty(
33 "sigma", "Sigma value", 0, 1.0f
34 );
35
36 private static final PropertyDescriptor minimumDescriptor = new DoubleProperty(
37 "minimum", "Minimum value", 0, 1.0f
38 );
39
40 private static final PropertyDescriptor topScoreDescriptor = new IntegerProperty(
41 "topscore", "Top score value", 0, 1.0f
42 );
43
44 private static final Map propertyDescriptorsByName = asFixedMap( new PropertyDescriptor[] {
45 sigmaDescriptor, minimumDescriptor, topScoreDescriptor
46 });
47
48
49 public void addDataPoint(DataPoint point) {
50 count++;
51 total += point.getScore();
52 dataPoints.add(point);
53 }
54
55 public void apply(List acus, RuleContext ctx) {
56 visitAll(acus, ctx);
57
58 double deviation;
59 double minimum = 0.0;
60
61 if (hasProperty("sigma")) {
62 deviation = getStdDev();
63 double sigma = getDoubleProperty(sigmaDescriptor);
64 minimum = getMean() + (sigma * deviation);
65 }
66
67 if (hasProperty("minimum")) {
68 double mMin = getDoubleProperty(minimumDescriptor);
69 if (mMin > minimum) {
70 minimum = mMin;
71 }
72 }
73
74 SortedSet newPoints = applyMinimumValue(dataPoints, minimum);
75
76 if (hasProperty("topscore")) {
77 int topScore = getIntProperty(topScoreDescriptor);
78 if (newPoints.size() >= topScore) {
79 newPoints = applyTopScore(newPoints, topScore);
80 }
81 }
82
83 makeViolations(ctx, newPoints);
84
85 double low = 0.0d;
86 double high = 0.0d;
87 if (!dataPoints.isEmpty()) {
88 low = ((DataPoint) dataPoints.first()).getScore();
89 high = ((DataPoint) dataPoints.last()).getScore();
90 }
91
92 ctx.getReport().addMetric(new Metric(this.getName(), count, total, low, high, getMean(), getStdDev()));
93
94 dataPoints.clear();
95 }
96
97 protected double getMean() {
98 return total / count;
99 }
100
101 protected double getStdDev() {
102 if (dataPoints.size() < 2) {
103 return Double.NaN;
104 }
105
106 Iterator points = dataPoints.iterator();
107 double mean = getMean();
108 double deltaSq = 0.0;
109 double scoreMinusMean;
110
111 while (points.hasNext()) {
112 scoreMinusMean = ((DataPoint) points.next()).getScore() - mean;
113 deltaSq += (scoreMinusMean * scoreMinusMean);
114 }
115
116 return Math.sqrt(deltaSq / (dataPoints.size() - 1));
117 }
118
119 protected SortedSet applyMinimumValue(SortedSet pointSet, double minValue) {
120 Iterator points = pointSet.iterator();
121 SortedSet RC = new TreeSet();
122 double threshold = minValue - DELTA;
123
124 while (points.hasNext()) {
125 DataPoint point = (DataPoint) points.next();
126
127 if (point.getScore() > threshold) {
128 RC.add(point);
129 }
130 }
131 return RC;
132 }
133
134 protected SortedSet applyTopScore(SortedSet points, int topScore) {
135 SortedSet s = new TreeSet();
136 Object[] arr = points.toArray();
137 for (int i = arr.length - 1; i >= (arr.length - topScore); i--) {
138 s.add(arr[i]);
139 }
140 return s;
141 }
142
143 protected void makeViolations(RuleContext ctx, Set p) {
144 Iterator points = p.iterator();
145 while (points.hasNext()) {
146 DataPoint point = (DataPoint) points.next();
147 addViolationWithMessage(ctx, point.getNode(), point.getMessage());
148 }
149 }
150
151 protected Map propertiesByName() {
152 return propertyDescriptorsByName;
153 }
154 }