001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd.stat;
004:
005: import java.util.List;
006: import java.util.Map;
007: import java.util.Set;
008: import java.util.SortedSet;
009: import java.util.TreeSet;
010:
011: import net.sourceforge.pmd.AbstractJavaRule;
012: import net.sourceforge.pmd.PropertyDescriptor;
013: import net.sourceforge.pmd.RuleContext;
014: import net.sourceforge.pmd.properties.DoubleProperty;
015: import net.sourceforge.pmd.properties.IntegerProperty;
016:
017: /**
018: * @author David Dixon-Peugh
019: * Aug 8, 2002 StatisticalRule.java
020: */
021: public abstract class StatisticalRule extends AbstractJavaRule {
022:
023: public static final double DELTA = 0.000005; // Within this range. . .
024:
025: private SortedSet<DataPoint> dataPoints = new TreeSet<DataPoint>();
026:
027: private int count = 0;
028: private double total = 0.0;
029:
030: private static final PropertyDescriptor sigmaDescriptor = new DoubleProperty(
031: "sigma", "Sigma value", 0, 1.0f);
032:
033: private static final PropertyDescriptor minimumDescriptor = new DoubleProperty(
034: "minimum", "Minimum value", 0, 1.0f);
035:
036: private static final PropertyDescriptor topScoreDescriptor = new IntegerProperty(
037: "topscore", "Top score value", 0, 1.0f);
038:
039: private static final Map<String, PropertyDescriptor> propertyDescriptorsByName = asFixedMap(new PropertyDescriptor[] {
040: sigmaDescriptor, minimumDescriptor, topScoreDescriptor });
041:
042: public void addDataPoint(DataPoint point) {
043: count++;
044: total += point.getScore();
045: dataPoints.add(point);
046: }
047:
048: public void apply(List acus, RuleContext ctx) {
049: visitAll(acus, ctx);
050:
051: double deviation;
052: double minimum = 0.0;
053:
054: if (hasProperty("sigma")) { // TODO - need to come up with a good default value
055: deviation = getStdDev();
056: double sigma = getDoubleProperty(sigmaDescriptor);
057: minimum = getMean() + (sigma * deviation);
058: }
059:
060: if (hasProperty("minimum")) { // TODO - need to come up with a good default value
061: double mMin = getDoubleProperty(minimumDescriptor);
062: if (mMin > minimum) {
063: minimum = mMin;
064: }
065: }
066:
067: SortedSet<DataPoint> newPoints = applyMinimumValue(dataPoints,
068: minimum);
069:
070: if (hasProperty("topscore")) { // TODO - need to come up with a good default value
071: int topScore = getIntProperty(topScoreDescriptor);
072: if (newPoints.size() >= topScore) {
073: newPoints = applyTopScore(newPoints, topScore);
074: }
075: }
076:
077: makeViolations(ctx, newPoints);
078:
079: double low = 0.0d;
080: double high = 0.0d;
081: if (!dataPoints.isEmpty()) {
082: low = dataPoints.first().getScore();
083: high = dataPoints.last().getScore();
084: }
085:
086: ctx.getReport().addMetric(
087: new Metric(this .getName(), count, total, low, high,
088: getMean(), getStdDev()));
089:
090: dataPoints.clear();
091: }
092:
093: protected double getMean() {
094: return total / count;
095: }
096:
097: protected double getStdDev() {
098: if (dataPoints.size() < 2) {
099: return Double.NaN;
100: }
101:
102: double mean = getMean();
103: double deltaSq = 0.0;
104: double scoreMinusMean;
105:
106: for (DataPoint point : dataPoints) {
107: scoreMinusMean = point.getScore() - mean;
108: deltaSq += (scoreMinusMean * scoreMinusMean);
109: }
110:
111: return Math.sqrt(deltaSq / (dataPoints.size() - 1));
112: }
113:
114: protected SortedSet<DataPoint> applyMinimumValue(
115: SortedSet<DataPoint> pointSet, double minValue) {
116: SortedSet<DataPoint> RC = new TreeSet<DataPoint>();
117: double threshold = minValue - DELTA;
118:
119: for (DataPoint point : pointSet) {
120: if (point.getScore() > threshold) {
121: RC.add(point);
122: }
123: }
124: return RC;
125: }
126:
127: protected SortedSet<DataPoint> applyTopScore(
128: SortedSet<DataPoint> points, int topScore) {
129: SortedSet<DataPoint> s = new TreeSet<DataPoint>();
130: DataPoint[] arr = points.toArray(new DataPoint[] {});
131: for (int i = arr.length - 1; i >= (arr.length - topScore); i--) {
132: s.add(arr[i]);
133: }
134: return s;
135: }
136:
137: protected void makeViolations(RuleContext ctx, Set<DataPoint> p) {
138: for (DataPoint point : p) {
139: addViolationWithMessage(ctx, point.getNode(), point
140: .getMessage());
141: }
142: }
143:
144: protected Map<String, PropertyDescriptor> propertiesByName() {
145: return propertyDescriptorsByName;
146: }
147: }
|