/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.stat; import net.sourceforge.pmd.AbstractRule; import net.sourceforge.pmd.RuleContext; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; /** * @author David Dixon-Peugh * Aug 8, 2002 StatisticalRule.java */ public abstract class StatisticalRule extends AbstractRule { public static double DELTA = 0.000005; // Within this range. . . private SortedSet dataPoints = new TreeSet(); private int count = 0; private double total = 0.0; private double totalSquared = 0.0; public void addDataPoint(DataPoint point) { count++; total += point.getScore(); totalSquared += point.getScore() * point.getScore(); dataPoints.add(point); } public void apply(List acus, RuleContext ctx) { visitAll(acus, ctx); double deviation; double minimum = 0.0; if (hasProperty("sigma")) { deviation = getStdDev(); double sigma = getDoubleProperty("sigma"); minimum = getMean() + (sigma * deviation); } if (hasProperty("minimum")) { double mMin = getDoubleProperty("minimum"); if (mMin > minimum) { minimum = mMin; } } SortedSet newPoints = applyMinimumValue(dataPoints, minimum); if (hasProperty("topscore")) { int topScore = getIntProperty("topscore"); if (newPoints.size() >= topScore) { newPoints = applyTopScore(newPoints, topScore); } } makeViolations(ctx, newPoints); double low = 0.0d; double high = 0.0d; if (!dataPoints.isEmpty()) { low = ((DataPoint) dataPoints.first()).getScore(); high = ((DataPoint) dataPoints.last()).getScore(); } ctx.getReport().addMetric(new Metric(this.getName(), count, total, low, high, getMean(), getStdDev())); dataPoints.clear(); } protected double getMean() { return total / count; } protected double getStdDev() { Iterator points = dataPoints.iterator(); double mean = getMean(); double deltaSq = 0.0; if (dataPoints.size() < 2) { return Double.NaN; } while (points.hasNext()) { DataPoint point = (DataPoint) points.next(); deltaSq += ((point.getScore() - mean) * (point.getScore() - mean)); } return Math.sqrt( deltaSq / (dataPoints.size() - 1)); } protected SortedSet applyMinimumValue(SortedSet pointSet, double minValue) { Iterator points = pointSet.iterator(); SortedSet RC = new TreeSet(); while (points.hasNext()) { DataPoint point = (DataPoint) points.next(); if (point.getScore() > (minValue - DELTA)) { RC.add(point); } } return RC; } protected SortedSet applyTopScore(SortedSet points, int topScore) { SortedSet RC = new TreeSet(); for (int i = 0; i < topScore; i++) { DataPoint point = (DataPoint) points.last(); points.remove(point); RC.add(point); } return RC; } protected void makeViolations(RuleContext ctx, Set dataPoints) { Iterator points = dataPoints.iterator(); while (points.hasNext()) { DataPoint point = (DataPoint) points.next(); ctx.getReport().addRuleViolation(this.createRuleViolation(ctx, point.getLineNumber(), point.getMessage())); } } }