Package pspdash

Source Code of pspdash.LognormalConfidenceInterval

// PSP Dashboard - Data Automation Tool for PSP-like processes
// Copyright (C) 2003 Software Process Dashboard Initiative
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// The author(s) may be contacted at:
// OO-ALC/TISHD
// Attn: PSP Dashboard Group
// 6137 Wardleigh Road
// Hill AFB, UT 84056-5843
//
// E-Mail POC:  processdash-devel@lists.sourceforge.net


package pspdash;

import java.util.*;

import org.w3c.dom.Element;

import DistLib.normal;
import DistLib.chisquare;
import DistLib.uniform;

public class LognormalConfidenceInterval extends AbstractConfidenceInterval {

    public LognormalConfidenceInterval() {
        // since this object is typically used to compare planned
        // values to actual values, the nominal input value of 1.0 is
        // a useful default.
        setInput(1.0);
    }


    /** Return the forecast value produced by translating the input
     * value according to correction algorithm contained in this
     * confidence interval.
     */
    public double getPrediction() {
        if (viability > ACCEPTABLE)
            return input * ratio;
        else
            return Double.NaN;
    }


    /** Obtain the given quantile of the distribution used to produce this
     * confidence interval, and translate the input value using that
     * number.
     */
    protected double getQuantile(double percentage) {
        if (samples == null) return Double.NaN;

        int pos = (int) ((1-percentage) * samples.length);
        if (pos < 0 || pos >= samples.length) return Double.NaN;

        double t = samples[pos];
        double logResult = base - t * rational;
        return Math.exp(logResult) * input;
    }


    /** Return a value indicating how viable this confidence interval
     * seems.
     */
    public double getViability() {
        return viability;
    }



    /** Add a historical data point
     */
    public void addDataPoint(double x, double y) {
        DataPoint lastPoint = null;
        if (dataPointsList != null && !dataPointsList.isEmpty())
            lastPoint = (DataPoint) dataPointsList.getLast();

        if (lastPoint != null &&
            ((x == 0 || lastPoint.x == 0) || (y == 0 || lastPoint.y == 0))) {
            // lognormal confidence intervals cannot deal well with
            // zero values.  If such a data point is encountered,
            // consolidate it with an adjacent data point.
            lastPoint.x += x;
            lastPoint.y += y;
        } else {
            super.addDataPoint(x, y);
        }
    }

    /** The ratio of total actual to total plan for all data points. */
    protected double ratio;
    /** The weighted lognormal mean of the actual-to-plan ratios */
    protected double logmean;
    /** The weighted lognormal standard deviation of the actual-to-plan ratios */
    protected double logstd;
    /** The samples generated by the bootstrap algorithm */
    protected double[] samples;
    /** A precalculated term in the calculation interval equation */
    protected double base;
    /** A precalculated term in the calculation interval equation */
    protected double rational;
    /** The calculated viability of the confidence interval */
    protected double viability = -1;


    public void dataPointsComplete() {
        super.dataPointsComplete();

        calcMeanStddev();
        calculateInterval(logmean, logstd);
    }

    protected void calculateInterval(double mean, double std) {
        logmean = mean;
        logstd = std;

        if (Double.isNaN(logmean) || Double.isInfinite(logmean) ||
            Double.isNaN(logstd|| Double.isInfinite(logstd||
            numSamples < 3) {
            viability = CANNOT_CALCULATE;
            return;
        }

        runParametricBootstrap();
        calcViability();
    }

    /** Calculate the ratio between actual and planned value for each data
     * point, then calculate the weighted lognormal mean and standard
     * deviation of these ratios.  (Planned values are used for weights.)
     *
     * This also calculates the overall linear ratio of total actual to
     * total plan.
     */
    private void calcMeanStddev() {
        numSamples = getNumPoints();
        double totalPlan = 0;
        double totalActual = 0;
        double[] logRatio = new double[numSamples];
        double sum = 0;

        for (int i = 0;   i < numSamples;   i++) {
            DataPoint p = getPoint(i);
            totalPlan += p.plan();
            totalActual += p.actual();
            logRatio[i] = Math.log(p.actual() / p.plan());
            sum += logRatio[i] * p.plan();
        }
        ratio = totalActual / totalPlan;
        logmean = sum / totalPlan;

        sum = 0;
        double diff;
        for (int i = 0;   i < numSamples;   i++) {
            DataPoint p = getPoint(i);
            diff = logRatio[i] - logmean;
            sum += diff * diff * p.plan();
        }
        logstd = Math.sqrt(sum * numSamples / ((numSamples - 1) * totalPlan));
    }

    private void runParametricBootstrap() {
        samples = generateBootstrapSamples();

        double s = logstd;
        double n = numSamples;
        rational = Math.sqrt((s*s*(1 + (s*s/2))) / n);
        base = logmean + s*s/2;
    }

    private double[] generateBootstrapSamples() {
        uniform u = new uniform();
        int bootstrapSize = Settings.getInt("logCI.bootstrapSize", 2000);
        double[] samples = new double[bootstrapSize];
        for (int i = bootstrapSize;   i-- > 0; )
             samples[i] = generateBootstrapSample(u, u, numSamples, logstd);
        Arrays.sort(samples);
        return samples;
    }


    /** Generate a single sample for the bootstrap algorithm.
     */
    private double generateBootstrapSample
        (uniform u1, uniform u2, int n, double sigma)
    {
        double N = normal.random(u1);
        double chi = chisquare.random(n-1, u2);
        double chiRatio = chi / (n-1);

        double numerator = N + sigma * Math.sqrt(n) * (chiRatio - 1.0) / 2.0;
        double denominator =
            Math.sqrt(chiRatio * (1.0 + sigma*sigma * chiRatio / 2.0));
        return numerator / denominator;
    }


    /** Heuristically estimate how viable this confidence interval appears
     * to be.
     */
    private void calcViability() {
        // perform the quantile() calculation backward, to determine what
        // probability percentage would yield a confidence interval that
        // includes the overall linear ratio between plan and actual.
        double range = Math.abs(Math.log(ratio) - base);
        double normRng = - range / rational;
        int pos = Math.abs(Arrays.binarySearch(samples, normRng));
        double prob = 2 * Math.abs((((double) pos) / samples.length) - 0.5);

        // what percentage does the user find acceptable?
        double cutoff = Settings.getInt("logCI.cutoffProbability", 50) / 100.0;
        if (prob > cutoff) {
            // the current probability is not acceptable.
            viability = SERIOUS_PROBLEM;
        } else {
            // use the percentage to scale the nominal viability rating.
            viability = NOMINAL * (1 - prob);
        }
    }

    protected void saveXMLAttributes(StringBuffer result) {
        result.append(" mean='").append(logmean)
            .append("' std='").append(logstd)
            .append("' ratio='").append(ratio)
            .append("' n='").append(numSamples)
            .append("'");
    }

    public LognormalConfidenceInterval(Element xml) {
        logmean = XMLUtils.getXMLNum(xml, "mean");
        logstd = XMLUtils.getXMLNum(xml, "std");
        ratio = XMLUtils.getXMLNum(xml, "ratio");
        numSamples = XMLUtils.getXMLInt(xml, "n");
        calculateInterval(logmean, logstd);
        setInput(1.0);
    }

}
TOP

Related Classes of pspdash.LognormalConfidenceInterval

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.