All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cloudbus.cloudsim.util.MathUtil Maven / Gradle / Ivy

/*
 * Title:        CloudSim Toolkit
 * Description:  CloudSim (Cloud Simulation) Toolkit for Modeling and Simulation of Clouds
 * Licence:      GPL - http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (c) 2009-2012, The University of Melbourne, Australia
 */

package org.cloudbus.cloudsim.util;

import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math3.stat.regression.OLSMultipleLinearRegression;
import org.apache.commons.math3.stat.regression.SimpleRegression;

import java.util.*;

/**
 * A class containing multiple convenient math functions.
 *
 * @author Anton Beloglazov
 * @since CloudSim Toolkit 3.0
 * @see TimeUtil
 */
public final class MathUtil {
    /**
     * 100% represented in scale [0 .. 1].
     */
    public static final double HUNDRED_PERCENT = 0.1;

    /**
     * A private constructor to avoid class instantiation.
     */
    private MathUtil(){}

    /**
     * Sums a list of numbers.
     *
     * @param list the list of numbers
     * @return the double
     */
    public static double sum(final List list) {
        double sum = 0.0;
        for (final Number number : list) {
            sum += number.doubleValue();
        }

        return sum;
    }

    /**
     * Gets the median from a list of numbers.
     *
     * @param list the list of numbers
     * @return the median
     */
    public static double median(final Collection list) {
        return getStatistics(list).getPercentile(50);
    }

    /**
     * Gets the median from an array of numbers.
     *
     * @param list the array of numbers
     * @return the median
     */
    public static double median(final double... list) {
        return getStatistics(list).getPercentile(50);
    }

    /**
     * Gets an object to compute descriptive statistics for an list of numbers.
     *
     * @param list the list of numbers. Must not be null.
     * @return descriptive statistics for the list of numbers.
     */
    public static DescriptiveStatistics getStatistics(final Collection list) {
        final DescriptiveStatistics stats = new DescriptiveStatistics();
        list.forEach(stats::addValue);
        return stats;
    }

    /**
     * Gets an object to compute descriptive statistics for an array of numbers.
     *
     * @param list the array of numbers. Must not be null.
     * @return descriptive statistics for the array of numbers.
     */
    public static DescriptiveStatistics getStatistics(final double... list) {
        return new DescriptiveStatistics(list);
    }

    /**
     * Gets the average from a list of numbers.
     * If the list is empty or contains just zeros, returns 0.
     *
     * @param list the list of numbers
     * @return the average
     */
    public static double mean(final List list) {
        if(list.isEmpty()){
            return 0;
        }

        return sum(list) / (double)list.size();
    }

    /**
     * Gets the Variance from a list of numbers.
     *
     * @param list the list of numbers
     * @return the variance
     */
    public static double variance(final List list) {
        long count = 0;
        double mean = mean(list);
        double deltaSum = 0.0;

        for(final double x : list) {
            count++;
            final double delta = x - mean;
            mean += delta / count;
            deltaSum += delta * (x - mean);
        }

        return deltaSum / (count - 1);
    }

    /**
     * Gets the Standard Deviation from a list of numbers.
     *
     * @param list the list of numbers
     * @return the standard deviation
     */
    public static double stDev(final List list) {
        return Math.sqrt(variance(list));
    }

    /**
     * Gets the Median Absolute Deviation (MAD) from a array of numbers.
     *
     * @param data the array of numbers
     * @return the mad
     */
    public static double mad(final double... data) {
        if (data.length == 0) {
            return 0;
        }

        final double median = median(data);
        final double[] deviationSum = new double[data.length];
        for (int i = 0; i < data.length; i++) {
            deviationSum[i] = Math.abs(median - data[i]);
        }

        return median(deviationSum);
    }

    /**
     * Gets the Inter-quartile Range (IQR)
     * from an array of numbers.
     *
     * @param data the array of numbers
     * @return the IQR
     */
    public static double iqr(final double... data) {
        Arrays.sort(data);
        final int quartile1 = (int) Math.round(0.25 * (data.length + 1)) - 1;
        final int quartile3 = (int) Math.round(0.75 * (data.length + 1)) - 1;
        return data[quartile3] - data[quartile1];
    }

    /**
     * Counts the number of values different of zero at the beginning of
     * an array.
     *
     * @param data the array of numbers
     * @return the number of values different of zero at the beginning of the array
     */
    public static int countNonZeroBeginning(final double... data) {
        int i = data.length - 1;
        while (i >= 0) {
            if (data[i--] != 0) {
                break;
            }
        }
        return i + 2;
    }

    /**
     * Gets the Local Regression (Loess) parameter estimates.
     *
     * @param y the dependent variable
     * @return the Loess parameter estimates
     */
    public static double[] getLoessParameterEstimates(final double... y) {
        final double[] x = createIndependentArray(y.length);
        return createWeightedLinearRegression(x, y, getTricubeWeights(y.length))
                .regress().getParameterEstimates();
    }

    /**
     * Creates an array representing the independent variable for
     * computing a linear regression.
     *
     * @param length the length of the array to create
     * @return
     */
    private static double[] createIndependentArray(final int length) {
        final double[] x = new double[length];
        for (int i = 0; i < length; i++) {
            x[i] = i + 1;
        }
        return x;
    }

    /**
     * Creates a a simple linear regression.
     * @param x the independent variable
     * @param y the dependent variable
     * @return
     */
    public static SimpleRegression createLinearRegression(final double[] x, final double[] y) {
        final SimpleRegression regression = new SimpleRegression();
        for (int i = 0; i < x.length; i++) {
            regression.addData(x[i], y[i]);
        }
        return regression;
    }

    /**
     * Creates a a multiple linear regression.
     * @param x the independent variable
     * @param y the dependent variable
     * @return
     */
    public static OLSMultipleLinearRegression createLinearRegression(final double[][] x, final double[] y)
    {
        final OLSMultipleLinearRegression regression = new OLSMultipleLinearRegression();
        regression.newSampleData(y, x);
        return regression;
    }

    /**
     * Creates a a weighted linear regression.
     * @param x the independent variable
     * @param y the dependent variable
     * @param weights the weights to apply to x and y
     * @return
     */
    private static SimpleRegression createWeightedLinearRegression(
        final double[] x, final double[] y, final double[] weights)
    {
        final double[] weightedX = new double[x.length];
        final double[] weightedY = new double[y.length];

        final long numZeroWeights = Arrays.stream(weights).filter(weight -> weight <= 0).count();

        for (int i = 0; i < x.length; i++) {
            if (numZeroWeights >= 0.4 * weights.length) {
                // See: http://www.ncsu.edu/crsc/events/ugw07/Presentations/Crooks_Qiao/Crooks_Qiao_Alt_Presentation.pdf
                weightedX[i] = Math.sqrt(weights[i]) * x[i];
                weightedY[i] = Math.sqrt(weights[i]) * y[i];
            } else {
                weightedX[i] = x[i];
                weightedY[i] = y[i];
            }
        }

        return createLinearRegression(weightedX, weightedY);
    }

    /**
     * Gets the robust loess parameter estimates.
     *
     * @param y the dependent variable
     * @return the robust loess parameter estimates
     */
    public static double[] getRobustLoessParameterEstimates(final double... y) {
        final double[] x = createIndependentArray(y.length);
        final SimpleRegression tricubeRegression =
                createWeightedLinearRegression(x, y, getTricubeWeights(y.length));
        final double[] residuals = new double[y.length];
        for (int i = 0; i < y.length; i++) {
            residuals[i] = y[i] - tricubeRegression.predict(x[i]);
        }
        final SimpleRegression tricubeBySqrRegression =
                createWeightedLinearRegression(x, y, getTricubeBisquareWeights(residuals));

        final double[] estimates = tricubeBySqrRegression.regress().getParameterEstimates();
        if (Double.isNaN(estimates[0]) || Double.isNaN(estimates[1])) {
            return tricubeRegression.regress().getParameterEstimates();
        }
        return estimates;
    }

    /**
     * Gets the tricube weigths.
     *
     * @param weightsNumber the number of weights
     * @return an array of tricube weigths with n elements
     */
    public static double[] getTricubeWeights(final int weightsNumber) {
        final double[] weights = new double[weightsNumber];
        final double top = weightsNumber - 1; //spread
        for (int i = 2; i < weightsNumber; i++) {
            final double k = Math.pow(1 - Math.pow((top - i) / top, 3), 3);
            weights[i] = k > 0 ? 1 / k : Double.MAX_VALUE;
        }

        weights[0] = weights[1] = weights[2];
        return weights;
    }

    /**
     * Gets the tricube bisquare weigths.
     *
     * @param residuals the residuals array
     * @return the tricube bisquare weigths
     */
    public static double[] getTricubeBisquareWeights(final double... residuals) {
        final double[] weights = getTricubeWeights(residuals.length);
        final double[] weights2 = new double[residuals.length];
        final double s6 = median(abs(residuals)) * 6;
        for (int i = 2; i < residuals.length; i++) {
            final double k = Math.pow(1 - Math.pow(residuals[i] / s6, 2), 2);
            weights2[i] = k > 0 ? (1 / k) * weights[i] : Double.MAX_VALUE;
        }

        weights2[0] = weights2[1] = weights2[2];
        return weights2;
    }

    /**
     * Gets the absolute values of an array of values
     *
     * @param data the array of values
     * @return a new array with the absolute value of each element in the given array.
     */
    public static double[] abs(final double... data) {
        final double[] result = new double[data.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.abs(data[i]);
        }
        return result;
    }

    /**
     * Converts a double value to an int, using an appropriate
     * rounding function.
     * If the double is negative, it applies {@link Math#floor(double)}
     * to round the number down. If it' a positive value, it
     * applies {@link Math#ceil(double)} to round the number up.
     * This way, a negative double will be converted to a negative int
     * and a positive double will be converted to a positive int.
     *
     * 

It's different from using: {@link Math#round(double)} which always * rounds to the next positive integer; {@link Math#floor(double)} which * always rounds down; or {@link Math#ceil(double)} which always * rounds up. It applies floor for negative values and ceil * for positive ones.

* *

This method is useful to be used by {@link Comparator}s which * rely on a double attribute to compare a list of objects. * Since the {@link Comparator#compare(Object, Object)} method * must return an int, the method being implemented here * converts a double to an int value which can be used by * a Comparator.

* * @param value the double value to convert * @return zero if the double value is zero, a negative int if the double is negative, * or a positive int if the double is positive. */ public static int doubleToInt(final double value){ return (int)(value < 0 ? Math.floor(value) : Math.ceil(value)); } /** * Try to convert a String to an int value. * If the conversion is not possible, returns a default value. * @param value the value to try converting * @param defaultValue the default value to return in case of error * @return the converted value or the default one in case of error */ public static int parseInt(final String value, final int defaultValue){ try { return Integer.parseInt(value); } catch(NumberFormatException e){ return defaultValue; } } /** * Checks if two double numbers are equals, considering a precision error or 0.01. * That is, if the different between the two numbers are lower or equal to 0.01, they are considered equal. * @param first the first number to check * @param second the second number to check * @return true if the numbers are equal considering the precision error */ public static boolean same(final double first, final double second){ return same(first,second, 0.01); } /** * Checks if two double numbers are equals, considering a given precision error. * That is, if the different between the two numbers are lower or equal to the precision error, they are considered equal. * @param first the first number to check * @param second the second number to check * @param precisionError the precision error used to compare the numbers * @return true if the numbers are equal considering the precision error */ public static boolean same(final double first, final double second, final double precisionError){ return Math.abs(first-second) <= precisionError; } /** * Computes correlation coefficients for a set of data. * * @param data the data to compute the correlation coefficients * @return the correlation coefficients */ public static List correlationCoefficients(final double[][] data) { final int rows = data.length; final int cols = data[0].length; final List correlationCoefficients = new LinkedList<>(); for (int i = 0; i < rows; i++) { final double[][] x = new double[rows - 1][cols]; int k = 0; for (int j = 0; j < rows; j++) { if (j != i) { x[k++] = data[j]; } } // Transpose the matrix so that it fits the linear model final double[][] xT = new Array2DRowRealMatrix(x).transpose().getData(); // RSquare is the "coefficient of determination" correlationCoefficients.add(createLinearRegression(xT, data[i]).calculateRSquared()); } return correlationCoefficients; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy