org.workflowsim.utils.DistributionGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.workflowsim.utils.DistributionGenerator.java

Source

/*
 * 
 *   Copyright 2013-2014 University Of Southern California
 * 
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 *   Unless required by applicable law or agreed to in writing,
 *   software distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 * 
 */
package org.workflowsim.utils;

import java.util.Arrays;
import org.apache.commons.math3.distribution.GammaDistribution;
import org.apache.commons.math3.distribution.LogNormalDistribution;
import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.distribution.RealDistribution;
import org.apache.commons.math3.distribution.WeibullDistribution;

/**
 * This is a OverheadDistributionGenrator for one typic overhead per level.
 *
 * @author Weiwei Chen
 * @since WorkflowSim Toolkit 1.0
 * @date Mar 11, 2014
 */
public class DistributionGenerator {

    protected DistributionFamily dist;
    protected double scale;
    protected double shape;
    protected double scale_prior;
    protected double shape_prior;
    protected double likelihood_prior;
    protected double[] samples;
    protected double[] cumulativeSamples;
    protected int cursor;
    protected final int SAMPLE_SIZE = 1500; //DistributionGenerator will automatically increase the size

    public enum DistributionFamily {

        LOGNORMAL, GAMMA, WEIBULL, NORMAL
    }

    /**
     *
     * @param dist
     * @param scale
     * @param shape
     */
    public DistributionGenerator(DistributionFamily dist, double scale, double shape) {
        this.dist = dist;
        this.scale = scale;
        this.shape = shape;
        this.scale_prior = scale;
        this.shape_prior = shape;
        RealDistribution distribution = getDistribution(scale, shape);
        samples = distribution.sample(SAMPLE_SIZE);
        updateCumulativeSamples();
        cursor = 0;
    }

    public DistributionGenerator(DistributionFamily dist, double scale, double shape, double a, double b,
            double c) {
        this(dist, scale, shape);
        this.scale_prior = b;
        this.shape_prior = a;
        this.likelihood_prior = c;
    }

    /**
     * Gets the sample data
     *
     * @return samples
     */
    public double[] getSamples() {
        return samples;
    }

    /**
     * Gets the cumulative Samples
     *
     * @return cumulativeSamples
     */
    public double[] getCumulativeSamples() {
        return cumulativeSamples;
    }

    /**
     * Extends the sample size
     */
    public void extendSamples() {
        double[] new_samples = getDistribution(scale, shape).sample(SAMPLE_SIZE);
        samples = concat(samples, new_samples);
        updateCumulativeSamples();
    }

    /**
     * Update cumulativeSamples from samples
     */
    public void updateCumulativeSamples() {
        cumulativeSamples = new double[samples.length];
        cumulativeSamples[0] = samples[0];
        for (int i = 1; i < samples.length; i++) {
            cumulativeSamples[i] = cumulativeSamples[i - 1] + samples[i];
        }
    }

    /**
     * Gets the Prior Knowledge based Estimation of samples
     *
     * @return delay
     */
    public double getPKEMean() {
        return this.shape_prior / this.scale_prior;
    }

    /**
     * Gets the average of samples
     *
     * @return average
     */
    public double getMean() {
        double sum = 0.0;
        for (int i = 0; i < cursor; i++) {
            sum += samples[i];
        }
        return sum / cursor;
    }

    /**
     * Gets the likelihood prior
     *
     * @return likelihood_prior
     */
    public double getLikelihoodPrior() {
        return this.likelihood_prior;
    }

    /**
     * Gets the Maximum Likelihood Estimation of samples based on the ftc paper
     *
     * @return the delay
     */
    public double getMLEMean() {
        double a = shape_prior, b = scale_prior;
        double sum = 0.0;

        for (int i = 0; i < cursor; i++) {
            switch (dist) {
            case GAMMA:
                sum += samples[i];
                break;
            case WEIBULL:
                sum += Math.pow(samples[i], likelihood_prior);
                break;
            }
        }
        double result = 0.0;
        switch (dist) {
        case GAMMA:
            result = (b + sum) / (a + cursor * likelihood_prior - 1);
            break;
        case WEIBULL:
            result = (b + sum) / (a + cursor + 1);
            break;
        default:
            break;
        }
        return result;
    }

    /**
     * Vary the distribution parameters but not the prior knowledge
     *
     * @param scale the first param
     * @param shape the second param
     */
    public void varyDistribution(double scale, double shape) {
        this.scale = scale;
        this.shape = shape;
        RealDistribution distribution = getDistribution(scale, shape);
        samples = distribution.sample(SAMPLE_SIZE);
        updateCumulativeSamples();
        //cursor = 0;
    }

    /**
     * Merge two arrays
     *
     * @param <T> array type
     * @param first first array
     * @param second second array
     * @return new array
     */
    public double[] concat(double[] first, double[] second) {
        double[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

    /**
     * Gets the next sample from samples
     *
     * @return delay
     */
    public double getNextSample() {
        while (cursor >= samples.length) {
            double[] new_samples = getDistribution(scale, shape).sample(SAMPLE_SIZE);
            samples = concat(samples, new_samples);
            updateCumulativeSamples();
        }
        double delay = samples[cursor];
        cursor++;
        return delay;
    }

    /**
     * Gets the RealDistribution with two parameters
     *
     * @param scale the first param scale
     * @param shape the second param shape
     * @return the RealDistribution Object
     */
    public RealDistribution getDistribution(double scale, double shape) {
        RealDistribution distribution = null;
        switch (this.dist) {
        case LOGNORMAL:
            distribution = new LogNormalDistribution(scale, shape);
            break;
        case WEIBULL:
            distribution = new WeibullDistribution(shape, scale);
            break;
        case GAMMA:
            distribution = new GammaDistribution(shape, scale);
            break;
        case NORMAL:
            //shape is the std, scale is the mean
            distribution = new NormalDistribution(scale, shape);
            break;
        default:
            break;
        }
        return distribution;
    }

    /**
     * Gets the scale parameter
     * @return scale
     */
    public double getScale() {
        return this.scale;
    }

    /**
     * Gets the shape parameter
     * @return shape
     */
    public double getShape() {
        return this.shape;
    }
}