diff --git a/commons-math-legacy/pom.xml b/commons-math-legacy/pom.xml index 06148bdfac..04f70542f4 100644 --- a/commons-math-legacy/pom.xml +++ b/commons-math-legacy/pom.xml @@ -56,6 +56,11 @@ commons-statistics-ranking + + org.apache.commons + commons-statistics-descriptive + + org.apache.commons commons-numbers-core diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/ml/clustering/KMeansPlusPlusClusterer.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/ml/clustering/KMeansPlusPlusClusterer.java index ffe122cf79..ebb533d4bb 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/ml/clustering/KMeansPlusPlusClusterer.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/ml/clustering/KMeansPlusPlusClusterer.java @@ -24,10 +24,9 @@ import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; import org.apache.commons.math4.legacy.ml.distance.DistanceMeasure; import org.apache.commons.math4.legacy.ml.distance.EuclideanDistance; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; import org.apache.commons.rng.UniformRandomProvider; import org.apache.commons.rng.simple.RandomSource; - +import org.apache.commons.statistics.descriptive.Variance; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -431,11 +430,11 @@ private T getPointFromLargestVarianceCluster(final Collection // compute the distance variance of the current cluster final Clusterable center = cluster.getCenter(); - final Variance stat = new Variance(); + final Variance stat = Variance.create(); for (final T point : cluster.getPoints()) { - stat.increment(distance(point, center)); + stat.accept(distance(point, center)); } - final double variance = stat.getResult(); + final double variance = stat.getAsDouble(); // select the cluster with the largest variance if (variance > maxVariance) { diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/ml/clustering/evaluation/SumOfClusterVariances.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/ml/clustering/evaluation/SumOfClusterVariances.java index 2188980a92..e81b68e183 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/ml/clustering/evaluation/SumOfClusterVariances.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/ml/clustering/evaluation/SumOfClusterVariances.java @@ -23,7 +23,7 @@ import org.apache.commons.math4.legacy.ml.clustering.Clusterable; import org.apache.commons.math4.legacy.ml.clustering.ClusterEvaluator; import org.apache.commons.math4.legacy.ml.distance.DistanceMeasure; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; +import org.apache.commons.statistics.descriptive.Variance; /** * Computes the sum of intra-cluster distance variances according to the formula: @@ -56,12 +56,12 @@ public double score(List> clusters) { final Clusterable center = cluster.centroid(); // compute the distance variance of the current cluster - final Variance stat = new Variance(); + final Variance stat = Variance.create(); for (final Clusterable point : cluster.getPoints()) { - stat.increment(distance(point, center)); + stat.accept(distance(point, center)); } - varianceSum += stat.getResult(); + varianceSum += stat.getAsDouble(); } } return varianceSum; diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/SimulatedAnnealing.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/SimulatedAnnealing.java index 3ce2c7d538..cdb819978e 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/SimulatedAnnealing.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/optim/nonlinear/scalar/SimulatedAnnealing.java @@ -19,7 +19,7 @@ import java.util.function.BiFunction; import java.util.function.DoublePredicate; import org.apache.commons.rng.UniformRandomProvider; -import org.apache.commons.math4.legacy.stat.descriptive.moment.StandardDeviation; +import org.apache.commons.statistics.descriptive.StandardDeviation; import org.apache.commons.math4.legacy.optim.OptimizationData; import org.apache.commons.math4.legacy.optim.nonlinear.scalar.noderiv.Simplex; @@ -164,11 +164,11 @@ static CoolingSchedule aarstAndVanLaarhoven(final double delta) { return (previousTemperature, simplex) -> { // Standard deviation of the values of the objective function. - final StandardDeviation stddev = new StandardDeviation(); + final StandardDeviation stddev = StandardDeviation.create(); for (int i = 0; i < simplex.getSize(); i++) { - stddev.increment(simplex.get(i).getValue()); + stddev.accept(simplex.get(i).getValue()); } - final double sigma = stddev.getResult(); + final double sigma = stddev.getAsDouble(); final double a = previousTemperature * Math.log(1 + delta); final double b = 3 * sigma; diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/StatUtils.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/StatUtils.java index 0fcd3e74ea..13531977e8 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/StatUtils.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/StatUtils.java @@ -17,26 +17,22 @@ package org.apache.commons.math4.legacy.stat; import java.util.List; - +import org.apache.commons.math4.legacy.core.MathArrays; import org.apache.commons.math4.legacy.exception.DimensionMismatchException; import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; import org.apache.commons.math4.legacy.exception.NoDataException; -import org.apache.commons.math4.legacy.exception.NotPositiveException; import org.apache.commons.math4.legacy.exception.NullArgumentException; import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException; import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; import org.apache.commons.math4.legacy.stat.descriptive.DescriptiveStatistics; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Max; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Min; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile; -import org.apache.commons.math4.legacy.stat.descriptive.summary.Product; -import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares; +import org.apache.commons.statistics.descriptive.GeometricMean; +import org.apache.commons.statistics.descriptive.Max; +import org.apache.commons.statistics.descriptive.Min; +import org.apache.commons.statistics.descriptive.Quantile; +import org.apache.commons.statistics.descriptive.Quantile.EstimationMethod; +import org.apache.commons.statistics.descriptive.Sum; +import org.apache.commons.statistics.descriptive.SumOfLogs; +import org.apache.commons.statistics.descriptive.SumOfSquares; /** * StatUtils provides static methods for computing statistics based on data @@ -44,35 +40,8 @@ */ public final class StatUtils { - /** sum. */ - private static final UnivariateStatistic SUM = new Sum(); - - /** sumSq. */ - private static final UnivariateStatistic SUM_OF_SQUARES = new SumOfSquares(); - - /** prod. */ - private static final UnivariateStatistic PRODUCT = new Product(); - - /** sumLog. */ - private static final UnivariateStatistic SUM_OF_LOGS = new SumOfLogs(); - - /** min. */ - private static final UnivariateStatistic MIN = new Min(); - - /** max. */ - private static final UnivariateStatistic MAX = new Max(); - - /** mean. */ - private static final UnivariateStatistic MEAN = new Mean(); - - /** variance. */ - private static final Variance VARIANCE = new Variance(); - /** percentile. */ - private static final Percentile PERCENTILE = new Percentile(); - - /** geometric mean. */ - private static final GeometricMean GEOMETRIC_MEAN = new GeometricMean(); + private static final Quantile QUANTILE = Quantile.withDefaults().with(EstimationMethod.HF6).withCopy(false); /** * Private Constructor. @@ -91,7 +60,10 @@ private StatUtils() { * @throws MathIllegalArgumentException if the array is null */ public static double sum(final double[] values) throws MathIllegalArgumentException { - return SUM.evaluate(values); + if (verifyValues(values)) { + return Sum.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -109,7 +81,10 @@ public static double sum(final double[] values) throws MathIllegalArgumentExcept */ public static double sum(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return SUM.evaluate(values, begin, length); + if (MathArrays.verifyValues(values, begin, length)) { + return Sum.ofRange(values, begin, begin + length).getAsDouble(); + } + return Double.NaN; } /** @@ -123,7 +98,10 @@ public static double sum(final double[] values, final int begin, final int lengt * @throws MathIllegalArgumentException if the array is null */ public static double sumSq(final double[] values) throws MathIllegalArgumentException { - return SUM_OF_SQUARES.evaluate(values); + if (verifyValues(values)) { + return SumOfSquares.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -142,7 +120,10 @@ public static double sumSq(final double[] values) throws MathIllegalArgumentExce */ public static double sumSq(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return SUM_OF_SQUARES.evaluate(values, begin, length); + if (MathArrays.verifyValues(values, begin, length)) { + return SumOfSquares.ofRange(values, begin, begin + length).getAsDouble(); + } + return Double.NaN; } /** @@ -156,7 +137,10 @@ public static double sumSq(final double[] values, final int begin, final int len * @throws MathIllegalArgumentException if the array is null */ public static double product(final double[] values) throws MathIllegalArgumentException { - return PRODUCT.evaluate(values); + if (verifyValues(values)) { + return org.apache.commons.statistics.descriptive.Product.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -175,7 +159,11 @@ public static double product(final double[] values) throws MathIllegalArgumentEx */ public static double product(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return PRODUCT.evaluate(values, begin, length); + if (MathArrays.verifyValues(values, begin, length)) { + return org.apache.commons.statistics.descriptive.Product.ofRange(values, begin, begin + length) + .getAsDouble(); + } + return Double.NaN; } /** @@ -183,15 +171,16 @@ public static double product(final double[] values, final int begin, final int l * Double.NaN if the array is empty. *

* Throws IllegalArgumentException if the array is null. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs}. * * @param values the input array * @return the sum of the natural logs of the values or Double.NaN if the array is empty * @throws MathIllegalArgumentException if the array is null */ public static double sumLog(final double[] values) throws MathIllegalArgumentException { - return SUM_OF_LOGS.evaluate(values); + if (verifyValues(values)) { + return SumOfLogs.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -199,8 +188,6 @@ public static double sumLog(final double[] values) throws MathIllegalArgumentExc * the input array, or Double.NaN if the designated subarray is empty. *

* Throws IllegalArgumentException if the array is null. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs}. * * @param values the input array * @param begin index of the first array element to include @@ -212,7 +199,10 @@ public static double sumLog(final double[] values) throws MathIllegalArgumentExc */ public static double sumLog(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return SUM_OF_LOGS.evaluate(values, begin, length); + if (MathArrays.verifyValues(values, begin, length)) { + return SumOfLogs.ofRange(values, begin, begin + length).getAsDouble(); + } + return Double.NaN; } /** @@ -220,16 +210,16 @@ public static double sumLog(final double[] values, final int begin, final int le * Double.NaN if the array is empty. *

* Throws IllegalArgumentException if the array is null. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Mean} for - * details on the computing algorithm. * * @param values the input array * @return the mean of the values or Double.NaN if the array is empty * @throws MathIllegalArgumentException if the array is null */ public static double mean(final double[] values) throws MathIllegalArgumentException { - return MEAN.evaluate(values); + if (verifyValues(values)) { + return org.apache.commons.statistics.descriptive.Mean.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -238,9 +228,6 @@ public static double mean(final double[] values) throws MathIllegalArgumentExcep * is empty. *

* Throws IllegalArgumentException if the array is null. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Mean Mean} for - * details on the computing algorithm. * * @param values the input array * @param begin index of the first array element to include @@ -251,7 +238,11 @@ public static double mean(final double[] values) throws MathIllegalArgumentExcep */ public static double mean(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return MEAN.evaluate(values, begin, length); + if (MathArrays.verifyValues(values, begin, length)) { + return org.apache.commons.statistics.descriptive.Mean.ofRange(values, begin, begin + length) + .getAsDouble(); + } + return Double.NaN; } /** @@ -259,16 +250,16 @@ public static double mean(final double[] values, final int begin, final int leng * Double.NaN if the array is empty. *

* Throws IllegalArgumentException if the array is null. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean GeometricMean} - * for details on the computing algorithm. * * @param values the input array * @return the geometric mean of the values or Double.NaN if the array is empty * @throws MathIllegalArgumentException if the array is null */ public static double geometricMean(final double[] values) throws MathIllegalArgumentException { - return GEOMETRIC_MEAN.evaluate(values); + if (verifyValues(values)) { + return GeometricMean.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -277,9 +268,6 @@ public static double geometricMean(final double[] values) throws MathIllegalArgu * is empty. *

* Throws IllegalArgumentException if the array is null. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean GeometricMean} - * for details on the computing algorithm. * * @param values the input array * @param begin index of the first array element to include @@ -290,7 +278,10 @@ public static double geometricMean(final double[] values) throws MathIllegalArgu */ public static double geometricMean(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return GEOMETRIC_MEAN.evaluate(values, begin, length); + if (MathArrays.verifyValues(values, begin, length)) { + return GeometricMean.ofRange(values, begin, begin + length).getAsDouble(); + } + return Double.NaN; } /** @@ -301,9 +292,6 @@ public static double geometricMean(final double[] values, final int begin, final * the denominator). Use {@link #populationVariance(double[])} for the non-bias-corrected * population variance. *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for - * details on the computing algorithm. - *

* Returns 0 for a single-value (i.e. length = 1) sample. *

* Throws MathIllegalArgumentException if the array is null. @@ -313,7 +301,10 @@ public static double geometricMean(final double[] values, final int begin, final * @throws MathIllegalArgumentException if the array is null */ public static double variance(final double[] values) throws MathIllegalArgumentException { - return VARIANCE.evaluate(values); + if (verifyValues(values)) { + return org.apache.commons.statistics.descriptive.Variance.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -325,9 +316,6 @@ public static double variance(final double[] values) throws MathIllegalArgumentE * the denominator). Use {@link #populationVariance(double[], int, int)} for the non-bias-corrected * population variance. *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for - * details on the computing algorithm. - *

* Returns 0 for a single-value (i.e. length = 1) sample. *

* Throws MathIllegalArgumentException if the array is null or the @@ -342,72 +330,11 @@ public static double variance(final double[] values) throws MathIllegalArgumentE */ public static double variance(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return VARIANCE.evaluate(values, begin, length); - } - - /** - * Returns the variance of the entries in the specified portion of - * the input array, using the precomputed mean value. Returns - * Double.NaN if the designated subarray is empty. - *

- * This method returns the bias-corrected sample variance (using {@code n - 1} in - * the denominator). Use {@link #populationVariance(double[], double, int, int)} for - * the non-bias-corrected population variance. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for - * details on the computing algorithm. - *

- * The formula used assumes that the supplied mean value is the arithmetic - * mean of the sample data, not a known population parameter. This method - * is supplied only to save computation when the mean has already been - * computed. - *

- * Returns 0 for a single-value (i.e. length = 1) sample. - *

- * Throws MathIllegalArgumentException if the array is null or the - * array index parameters are not valid. - * - * @param values the input array - * @param mean the precomputed mean value - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the variance of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - public static double variance(final double[] values, final double mean, final int begin, final int length) - throws MathIllegalArgumentException { - return VARIANCE.evaluate(values, mean, begin, length); - } - - /** - * Returns the variance of the entries in the input array, using the - * precomputed mean value. Returns Double.NaN if the array - * is empty. - *

- * This method returns the bias-corrected sample variance (using {@code n - 1} in - * the denominator). Use {@link #populationVariance(double[], double)} for the - * non-bias-corrected population variance. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for - * details on the computing algorithm. - *

- * The formula used assumes that the supplied mean value is the arithmetic - * mean of the sample data, not a known population parameter. This method - * is supplied only to save computation when the mean has already been - * computed. - *

- * Returns 0 for a single-value (i.e. length = 1) sample. - *

- * Throws MathIllegalArgumentException if the array is null. - * - * @param values the input array - * @param mean the precomputed mean value - * @return the variance of the values or Double.NaN if the array is empty - * @throws MathIllegalArgumentException if the array is null - */ - public static double variance(final double[] values, final double mean) throws MathIllegalArgumentException { - return VARIANCE.evaluate(values, mean); + if (MathArrays.verifyValues(values, begin, length)) { + return org.apache.commons.statistics.descriptive.Variance.ofRange(values, begin, begin + length) + .getAsDouble(); + } + return Double.NaN; } /** @@ -415,9 +342,6 @@ public static double variance(final double[] values, final double mean) throws M * population variance of the entries in the input array, or * Double.NaN if the array is empty. *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for - * details on the formula and computing algorithm. - *

* Returns 0 for a single-value (i.e. length = 1) sample. *

* Throws MathIllegalArgumentException if the array is null. @@ -427,7 +351,11 @@ public static double variance(final double[] values, final double mean) throws M * @throws MathIllegalArgumentException if the array is null */ public static double populationVariance(final double[] values) throws MathIllegalArgumentException { - return new Variance(false).evaluate(values); + if (verifyValues(values)) { + return org.apache.commons.statistics.descriptive.Variance.of(values) + .setBiased(true).getAsDouble(); + } + return Double.NaN; } /** @@ -436,9 +364,6 @@ public static double populationVariance(final double[] values) throws MathIllega * the input array, or Double.NaN if the designated subarray * is empty. *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for - * details on the computing algorithm. - *

* Returns 0 for a single-value (i.e. length = 1) sample. *

* Throws MathIllegalArgumentException if the array is null or the @@ -453,66 +378,11 @@ public static double populationVariance(final double[] values) throws MathIllega */ public static double populationVariance(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return new Variance(false).evaluate(values, begin, length); - } - - /** - * Returns the - * population variance of the entries in the specified portion of - * the input array, using the precomputed mean value. Returns - * Double.NaN if the designated subarray is empty. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for - * details on the computing algorithm. - *

- * The formula used assumes that the supplied mean value is the arithmetic - * mean of the sample data, not a known population parameter. This method - * is supplied only to save computation when the mean has already been - * computed. - *

- * Returns 0 for a single-value (i.e. length = 1) sample. - *

- * Throws MathIllegalArgumentException if the array is null or the - * array index parameters are not valid. - * - * @param values the input array - * @param mean the precomputed mean value - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the population variance of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - public static double populationVariance(final double[] values, final double mean, - final int begin, final int length) - throws MathIllegalArgumentException { - return new Variance(false).evaluate(values, mean, begin, length); - } - - /** - * Returns the - * population variance of the entries in the input array, using the precomputed - * mean value. Returns Double.NaN if the array is empty. - *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for - * details on the computing algorithm. - *

- * The formula used assumes that the supplied mean value is the arithmetic - * mean of the sample data, not a known population parameter. This method is - * supplied only to save computation when the mean has already been computed. - *

- * Returns 0 for a single-value (i.e. length = 1) sample. - *

- * Throws MathIllegalArgumentException if the array is null. - * - * @param values the input array - * @param mean the precomputed mean value - * @return the population variance of the values or Double.NaN if the array is empty - * @throws MathIllegalArgumentException if the array is null - */ - public static double populationVariance(final double[] values, final double mean) - throws MathIllegalArgumentException { - return new Variance(false).evaluate(values, mean); + if (MathArrays.verifyValues(values, begin, length)) { + return org.apache.commons.statistics.descriptive.Variance.ofRange(values, begin, begin + length) + .setBiased(true).getAsDouble(); + } + return Double.NaN; } /** @@ -520,19 +390,16 @@ public static double populationVariance(final double[] values, final double mean * Double.NaN if the array is empty. *

* Throws MathIllegalArgumentException if the array is null. - *

* * @param values the input array * @return the maximum of the values or Double.NaN if the array is empty * @throws MathIllegalArgumentException if the array is null */ public static double max(final double[] values) throws MathIllegalArgumentException { - return MAX.evaluate(values); + if (verifyValues(values)) { + return Max.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -541,12 +408,6 @@ public static double max(final double[] values) throws MathIllegalArgumentExcept *

* Throws MathIllegalArgumentException if the array is null or * the array index parameters are not valid. - *

* * @param values the input array * @param begin index of the first array element to include @@ -557,7 +418,10 @@ public static double max(final double[] values) throws MathIllegalArgumentExcept */ public static double max(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return MAX.evaluate(values, begin, length); + if (MathArrays.verifyValues(values, begin, length)) { + return Max.ofRange(values, begin, begin + length).getAsDouble(); + } + return Double.NaN; } /** @@ -565,19 +429,16 @@ public static double max(final double[] values, final int begin, final int lengt * Double.NaN if the array is empty. *

* Throws MathIllegalArgumentException if the array is null. - *

* * @param values the input array * @return the minimum of the values or Double.NaN if the array is empty * @throws MathIllegalArgumentException if the array is null */ public static double min(final double[] values) throws MathIllegalArgumentException { - return MIN.evaluate(values); + if (verifyValues(values)) { + return Min.of(values).getAsDouble(); + } + return Double.NaN; } /** @@ -586,12 +447,6 @@ public static double min(final double[] values) throws MathIllegalArgumentExcept *

* Throws MathIllegalArgumentException if the array is null or * the array index parameters are not valid. - *

* * @param values the input array * @param begin index of the first array element to include @@ -602,7 +457,10 @@ public static double min(final double[] values) throws MathIllegalArgumentExcept */ public static double min(final double[] values, final int begin, final int length) throws MathIllegalArgumentException { - return MIN.evaluate(values, begin, length); + if (MathArrays.verifyValues(values, begin, length)) { + return Min.ofRange(values, begin, begin + length).getAsDouble(); + } + return Double.NaN; } /** @@ -618,16 +476,16 @@ public static double min(final double[] values, final int begin, final int lengt * and less than or equal to 100) * *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile Percentile} - * for a description of the percentile estimation algorithm used. + * See Commons Statistics {@link Quantile} for a description of the percentile estimation algorithm used. * * @param values input array of values * @param p the percentile value to compute * @return the percentile value or Double.NaN if the array is empty - * @throws MathIllegalArgumentException if values is null or p is invalid + * @throws IllegalArgumentException if values is null or p is invalid */ public static double percentile(final double[] values, final double p) throws MathIllegalArgumentException { - return PERCENTILE.evaluate(values,p); + verifyValues(values); + return QUANTILE.evaluate(values, p / 100); } /** @@ -645,19 +503,19 @@ public static double percentile(final double[] values, final double p) throws Ma * and less than or equal to 100) * *

- * See {@link org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile Percentile} - * for a description of the percentile estimation algorithm used. + * See Commons Statistics {@link Quantile} for a description of the percentile estimation algorithm used. * * @param values array of input values * @param p the percentile to compute * @param begin the first (0-based) element to include in the computation * @param length the number of array elements to include * @return the percentile value - * @throws MathIllegalArgumentException if the parameters are not valid or the input array is null + * @throws IllegalArgumentException if the parameters are not valid or the input array is null */ public static double percentile(final double[] values, final int begin, final int length, final double p) throws MathIllegalArgumentException { - return PERCENTILE.evaluate(values, begin, length, p); + MathArrays.verifyValues(values, begin, length); + return QUANTILE.evaluateRange(values, begin, begin + length, p / 100); } /** @@ -786,9 +644,8 @@ public static double[] normalize(final double[] sample) { * @since 3.3 */ public static double[] mode(double[] sample) throws MathIllegalArgumentException { - if (sample == null) { - throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); - } + // Zero length is allowed + verifyValues(sample); return getMode(sample, 0, sample.length); } @@ -816,18 +673,7 @@ public static double[] mode(double[] sample) throws MathIllegalArgumentException * @since 3.3 */ public static double[] mode(double[] sample, final int begin, final int length) { - if (sample == null) { - throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); - } - - if (begin < 0) { - throw new NotPositiveException(LocalizedFormats.START_POSITION, Integer.valueOf(begin)); - } - - if (length < 0) { - throw new NotPositiveException(LocalizedFormats.LENGTH, Integer.valueOf(length)); - } - + MathArrays.verifyValues(sample, begin, length); return getMode(sample, begin, length); } @@ -852,4 +698,18 @@ private static double[] getMode(double[] values, final int begin, final int leng // Convert the list to an array of primitive double return list.stream().mapToDouble(Double::doubleValue).toArray(); } + + /** + * This method is used to verify an array of positive length. + * + * @param values the input array + * @return true if the array is non-zero length + * @throws MathIllegalArgumentException if the array is null + */ + private static boolean verifyValues(final double[] values) { + if (values == null) { + throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); + } + return values.length != 0; + } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/correlation/Covariance.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/correlation/Covariance.java index 3677ffa278..5caf26ef65 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/correlation/Covariance.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/correlation/Covariance.java @@ -21,8 +21,6 @@ import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; import org.apache.commons.math4.legacy.linear.BlockRealMatrix; import org.apache.commons.math4.legacy.linear.RealMatrix; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; /** * Computes covariances for pairs of arrays or columns of a matrix. @@ -162,7 +160,6 @@ public int getN() { protected RealMatrix computeCovarianceMatrix(RealMatrix matrix, boolean biasCorrected) throws MathIllegalArgumentException { int dimension = matrix.getColumnDimension(); - Variance variance = new Variance(biasCorrected); RealMatrix outMatrix = new BlockRealMatrix(dimension, dimension); for (int i = 0; i < dimension; i++) { for (int j = 0; j < i; j++) { @@ -170,7 +167,8 @@ protected RealMatrix computeCovarianceMatrix(RealMatrix matrix, boolean biasCorr outMatrix.setEntry(i, j, cov); outMatrix.setEntry(j, i, cov); } - outMatrix.setEntry(i, i, variance.evaluate(matrix.getColumn(i))); + outMatrix.setEntry(i, i, org.apache.commons.statistics.descriptive.Variance.of( + matrix.getColumn(i)).setBiased(!biasCorrected).getAsDouble()); } return outMatrix; } @@ -233,7 +231,6 @@ protected RealMatrix computeCovarianceMatrix(double[][] data) */ public double covariance(final double[] xArray, final double[] yArray, boolean biasCorrected) throws MathIllegalArgumentException { - Mean mean = new Mean(); double result = 0d; int length = xArray.length; if (length != yArray.length) { @@ -243,8 +240,8 @@ public double covariance(final double[] xArray, final double[] yArray, boolean b throw new MathIllegalArgumentException( LocalizedFormats.INSUFFICIENT_OBSERVED_POINTS_IN_SAMPLE, length, 2); } else { - double xMean = mean.evaluate(xArray); - double yMean = mean.evaluate(yArray); + double xMean = org.apache.commons.statistics.descriptive.Mean.of(xArray).getAsDouble(); + double yMean = org.apache.commons.statistics.descriptive.Mean.of(yArray).getAsDouble(); for (int i = 0; i < length; i++) { double xDev = xArray[i] - xMean; double yDev = yArray[i] - yMean; diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/AbstractStorelessUnivariateStatistic.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/AbstractStorelessUnivariateStatistic.java index 1ea77e0f53..b85402d8b6 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/AbstractStorelessUnivariateStatistic.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/AbstractStorelessUnivariateStatistic.java @@ -20,7 +20,6 @@ import org.apache.commons.math4.legacy.exception.NullArgumentException; import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; import org.apache.commons.math4.legacy.core.MathArrays; -import org.apache.commons.numbers.core.Precision; /** * Abstract base class for implementations of the @@ -155,36 +154,4 @@ public void incrementAll(double[] values, int begin, int length) throws MathIlle } } } - - /** - * Returns true iff object is the same type of - * {@link StorelessUnivariateStatistic} (the object's class equals this - * instance) returning the same values as this for getResult() - * and getN(). - * - * @param object object to test equality against. - * @return true if object returns the same value as this - */ - @Override - public boolean equals(Object object) { - if (object == this ) { - return true; - } - if (object == null || object.getClass() != this.getClass()) { - return false; - } - StorelessUnivariateStatistic stat = (StorelessUnivariateStatistic) object; - return Precision.equalsIncludingNaN(stat.getResult(), this.getResult()) && - Precision.equalsIncludingNaN(stat.getN(), this.getN()); - } - - /** - * Returns hash code based on getResult() and getN(). - * - * @return hash code - */ - @Override - public int hashCode() { - return 31 * (31 + Double.hashCode(getResult())) + Double.hashCode(getN()); - } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/AggregateSummaryStatistics.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/AggregateSummaryStatistics.java index 1807e5c97e..058e7ebff3 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/AggregateSummaryStatistics.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/AggregateSummaryStatistics.java @@ -19,7 +19,7 @@ import java.util.Collection; import java.util.Iterator; - +import org.apache.commons.math4.core.jdkmath.JdkMath; import org.apache.commons.math4.legacy.exception.NullArgumentException; /** @@ -209,56 +209,6 @@ public double getVariance() { } } - /** - * Returns the sum of the logs of all the aggregated data. - * - * @return the sum of logs - * @see SummaryStatistics#getSumOfLogs() - */ - public double getSumOfLogs() { - synchronized (statistics) { - return statistics.getSumOfLogs(); - } - } - - /** - * Returns the geometric mean of all the aggregated data. - * - * @return the geometric mean - * @see SummaryStatistics#getGeometricMean() - */ - public double getGeometricMean() { - synchronized (statistics) { - return statistics.getGeometricMean(); - } - } - - /** - * Returns the sum of the squares of all the aggregated data. - * - * @return The sum of squares - * @see SummaryStatistics#getSumsq() - */ - public double getSumsq() { - synchronized (statistics) { - return statistics.getSumsq(); - } - } - - /** - * Returns a statistic related to the Second Central Moment. Specifically, - * what is returned is the sum of squared deviations from the sample mean - * among the all of the aggregated data. - * - * @return second central moment statistic - * @see SummaryStatistics#getSecondMoment() - */ - public double getSecondMoment() { - synchronized (statistics) { - return statistics.getSecondMoment(); - } - } - /** * Return a {@link StatisticalSummaryValues} instance reporting current * aggregate statistics. @@ -315,17 +265,13 @@ public static StatisticalSummaryValues aggregate(Collection max || Double.isNaN(max)) { - max = current.getMax(); - } + min = JdkMath.min(min, current.getMin()); + max = JdkMath.max(max, current.getMax()); sum += current.getSum(); final double oldN = n; final double curN = current.getN(); @@ -353,12 +299,6 @@ public static StatisticalSummaryValues aggregate(Collectionobject is a - * SummaryStatistics instance and all statistics have the - * same values as this. - * @param object the object to test equality against. - * @return true if object equals this - */ - @Override - public boolean equals(Object object) { - if (object == this) { - return true; - } - if (!(object instanceof AggregatingSummaryStatistics)) { - return false; - } - AggregatingSummaryStatistics stat = (AggregatingSummaryStatistics)object; - return super.equals(stat) && - aggregateStatistics.equals(stat.aggregateStatistics); - } - - /** - * Returns hash code based on values of statistics. - * @return hash code - */ - @Override - public int hashCode() { - return 123 + super.hashCode() + aggregateStatistics.hashCode(); - } } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/DescriptiveStatistics.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/DescriptiveStatistics.java index 383fd77749..36ba82bcc7 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/DescriptiveStatistics.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/DescriptiveStatistics.java @@ -19,21 +19,21 @@ import java.lang.reflect.InvocationTargetException; import java.util.Arrays; +import org.apache.commons.math4.core.jdkmath.JdkMath; import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; import org.apache.commons.math4.legacy.exception.MathIllegalStateException; import org.apache.commons.math4.legacy.exception.NullArgumentException; import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; -import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Kurtosis; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Skewness; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Max; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Min; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile; -import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares; -import org.apache.commons.math4.core.jdkmath.JdkMath; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.GeometricMean; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Kurtosis; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Max; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Mean; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Min; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Percentile; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Skewness; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Sum; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.SumOfSquares; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Variance; /** @@ -74,34 +74,34 @@ public class DescriptiveStatistics implements StatisticalSummary { private ResizableDoubleArray eDA = new ResizableDoubleArray(); /** Mean statistic implementation - can be reset by setter. */ - private UnivariateStatistic meanImpl = new Mean(); + private UnivariateStatistic meanImpl = Mean.getInstance(); /** Geometric mean statistic implementation - can be reset by setter. */ - private UnivariateStatistic geometricMeanImpl = new GeometricMean(); + private UnivariateStatistic geometricMeanImpl = GeometricMean.getInstance(); /** Kurtosis statistic implementation - can be reset by setter. */ - private UnivariateStatistic kurtosisImpl = new Kurtosis(); + private UnivariateStatistic kurtosisImpl = Kurtosis.getInstance(); /** Maximum statistic implementation - can be reset by setter. */ - private UnivariateStatistic maxImpl = new Max(); + private UnivariateStatistic maxImpl = Max.getInstance(); /** Minimum statistic implementation - can be reset by setter. */ - private UnivariateStatistic minImpl = new Min(); + private UnivariateStatistic minImpl = Min.getInstance(); /** Percentile statistic implementation - can be reset by setter. */ - private UnivariateStatistic percentileImpl = new Percentile(); + private UnivariateStatistic percentileImpl = Percentile.create(50); /** Skewness statistic implementation - can be reset by setter. */ - private UnivariateStatistic skewnessImpl = new Skewness(); + private UnivariateStatistic skewnessImpl = Skewness.getInstance(); /** Variance statistic implementation - can be reset by setter. */ - private UnivariateStatistic varianceImpl = new Variance(); + private UnivariateStatistic varianceImpl = Variance.getInstance(); /** Sum of squares statistic implementation - can be reset by setter. */ - private UnivariateStatistic sumsqImpl = new SumOfSquares(); + private UnivariateStatistic sumsqImpl = SumOfSquares.getInstance(); /** Sum statistic implementation - can be reset by setter. */ - private UnivariateStatistic sumImpl = new Sum(); + private UnivariateStatistic sumImpl = Sum.getInstance(); /** * Construct a {@code DescriptiveStatistics} instance with an infinite @@ -236,8 +236,7 @@ public double getGeometricMean() { * Returns the (sample) variance of the available values. * *

This method returns the bias-corrected sample variance (using {@code n - 1} in - * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected - * population variance.

+ * the denominator).

* * @return The variance, Double.NaN if no values have been added * or 0.0 for a single value set. @@ -247,17 +246,6 @@ public double getVariance() { return apply(varianceImpl); } - /** - * Returns the - * population variance of the available values. - * - * @return The population variance, Double.NaN if no values have been added, - * or 0.0 for a single value set. - */ - public double getPopulationVariance() { - return apply(new Variance(false)); - } - /** * Returns the standard deviation of the available values. * @return The standard deviation, Double.NaN if no values have been added @@ -461,9 +449,8 @@ public double getPercentile(double p) throws MathIllegalStateException, MathIlle ((Percentile) percentileImpl).setQuantile(p); } else { try { - percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME, - new Class[] {Double.TYPE}).invoke(percentileImpl, - new Object[] {Double.valueOf(p)}); + percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME, Double.TYPE) + .invoke(percentileImpl, Double.valueOf(p)); } catch (NoSuchMethodException e1) { // Setter guard should prevent throw new MathIllegalStateException( LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD, @@ -650,9 +637,8 @@ public synchronized UnivariateStatistic getPercentileImpl() { public synchronized void setPercentileImpl(UnivariateStatistic percentileImpl) throws MathIllegalArgumentException { try { - percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME, - new Class[] {Double.TYPE}).invoke(percentileImpl, - new Object[] {Double.valueOf(50.0d)}); + percentileImpl.getClass().getMethod(SET_QUANTILE_METHOD_NAME, Double.TYPE) + .invoke(percentileImpl, Double.valueOf(50.0d)); } catch (NoSuchMethodException e1) { throw new MathIllegalArgumentException( LocalizedFormats.PERCENTILE_IMPLEMENTATION_UNSUPPORTED_METHOD, @@ -789,8 +775,8 @@ public static void copy(DescriptiveStatistics source, DescriptiveStatistics dest dest.varianceImpl = source.varianceImpl.copy(); dest.sumsqImpl = source.sumsqImpl.copy(); dest.geometricMeanImpl = source.geometricMeanImpl.copy(); - dest.kurtosisImpl = source.kurtosisImpl; - dest.skewnessImpl = source.skewnessImpl; - dest.percentileImpl = source.percentileImpl; + dest.kurtosisImpl = source.kurtosisImpl.copy(); + dest.skewnessImpl = source.skewnessImpl.copy(); + dest.percentileImpl = source.percentileImpl.copy(); } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/MultivariateSummaryStatistics.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/MultivariateSummaryStatistics.java index 60cdf77c28..2ca4a4a60f 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/MultivariateSummaryStatistics.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/MultivariateSummaryStatistics.java @@ -22,17 +22,15 @@ import org.apache.commons.math4.legacy.exception.MathIllegalStateException; import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; import org.apache.commons.math4.legacy.linear.RealMatrix; -import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; import org.apache.commons.math4.legacy.stat.descriptive.moment.VectorialCovariance; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Max; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Min; -import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessGeometricMean; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessMax; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessMean; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessMin; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessSum; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessSumOfLogs; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessSumOfSquares; import org.apache.commons.math4.core.jdkmath.JdkMath; -import org.apache.commons.math4.legacy.core.MathArrays; -import org.apache.commons.numbers.core.Precision; /** *

Computes summary statistics for a stream of n-tuples added using the @@ -117,13 +115,13 @@ public MultivariateSummaryStatistics(int k, boolean isCovarianceBiasCorrected) { meanImpl = new StorelessUnivariateStatistic[k]; for (int i = 0; i < k; ++i) { - sumImpl[i] = new Sum(); - sumSqImpl[i] = new SumOfSquares(); - minImpl[i] = new Min(); - maxImpl[i] = new Max(); - sumLogImpl[i] = new SumOfLogs(); - geoMeanImpl[i] = new GeometricMean(); - meanImpl[i] = new Mean(); + sumImpl[i] = StorelessSum.create(); + sumSqImpl[i] = StorelessSumOfSquares.create(); + minImpl[i] = StorelessMin.create(); + maxImpl[i] = StorelessMax.create(); + sumLogImpl[i] = StorelessSumOfLogs.create(); + geoMeanImpl[i] = StorelessGeometricMean.create(); + meanImpl[i] = StorelessMean.create(); } covarianceImpl = @@ -362,52 +360,6 @@ public void clear() { covarianceImpl.clear(); } - /** - * Returns true iff object is a MultivariateSummaryStatistics - * instance and all statistics have the same values as this. - * @param object the object to test equality against. - * @return true if object equals this - */ - @Override - public boolean equals(Object object) { - if (object == this ) { - return true; - } - if (!(object instanceof MultivariateSummaryStatistics)) { - return false; - } - MultivariateSummaryStatistics stat = (MultivariateSummaryStatistics) object; - return MathArrays.equalsIncludingNaN(stat.getGeometricMean(), getGeometricMean()) && - MathArrays.equalsIncludingNaN(stat.getMax(), getMax()) && - MathArrays.equalsIncludingNaN(stat.getMean(), getMean()) && - MathArrays.equalsIncludingNaN(stat.getMin(), getMin()) && - Precision.equalsIncludingNaN(stat.getN(), getN()) && - MathArrays.equalsIncludingNaN(stat.getSum(), getSum()) && - MathArrays.equalsIncludingNaN(stat.getSumSq(), getSumSq()) && - MathArrays.equalsIncludingNaN(stat.getSumLog(), getSumLog()) && - stat.getCovariance().equals( getCovariance()); - } - - /** - * Returns hash code based on values of statistics. - * - * @return hash code - */ - @Override - public int hashCode() { - int result = 31 + Arrays.hashCode(getGeometricMean()); - result = result * 31 + Arrays.hashCode(getGeometricMean()); - result = result * 31 + Arrays.hashCode(getMax()); - result = result * 31 + Arrays.hashCode(getMean()); - result = result * 31 + Arrays.hashCode(getMin()); - result = result * 31 + Double.hashCode(getN()); - result = result * 31 + Arrays.hashCode(getSum()); - result = result * 31 + Arrays.hashCode(getSumSq()); - result = result * 31 + Arrays.hashCode(getSumLog()); - result = result * 31 + getCovariance().hashCode(); - return result; - } - // Getters and setters for statistics implementations /** * Sets statistics implementations. diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/ResizableDoubleArray.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/ResizableDoubleArray.java index 0b3034c57e..47b075f923 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/ResizableDoubleArray.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/ResizableDoubleArray.java @@ -16,8 +16,6 @@ */ package org.apache.commons.math4.legacy.stat.descriptive; -import java.util.Arrays; - import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; import org.apache.commons.math4.legacy.exception.MathIllegalStateException; import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; @@ -794,53 +792,4 @@ private boolean shouldContract() { public ResizableDoubleArray copy() { return new ResizableDoubleArray(this); } - - /** - * Returns true iff object is a ResizableDoubleArray with the same properties - * as this and an identical internal storage array. - * - * @param object object to be compared for equality with this - * @return true iff object is a ResizableDoubleArray with the same data and - * properties as this - * @since 2.0 - */ - @Override - public boolean equals(Object object) { - if (object == this ) { - return true; - } - if (!(object instanceof ResizableDoubleArray)) { - return false; - } - boolean result = true; - final ResizableDoubleArray other = (ResizableDoubleArray) object; - result = result && other.contractionCriterion == contractionCriterion; - result = result && other.expansionFactor == expansionFactor; - result = result && other.expansionMode == expansionMode; - result = result && other.numElements == numElements; - result = result && other.startIndex == startIndex; - if (!result) { - return false; - } else { - return Arrays.equals(internalArray, other.internalArray); - } - } - - /** - * Returns a hash code consistent with equals. - * - * @return the hash code representing this {@code ResizableDoubleArray}. - * @since 2.0 - */ - @Override - public int hashCode() { - final int[] hashData = new int[6]; - hashData[0] = Double.valueOf(expansionFactor).hashCode(); - hashData[1] = Double.valueOf(contractionCriterion).hashCode(); - hashData[2] = expansionMode.hashCode(); - hashData[3] = Arrays.hashCode(internalArray); - hashData[4] = numElements; - hashData[5] = startIndex; - return Arrays.hashCode(hashData); - } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticalSummaryValues.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticalSummaryValues.java index 135febce10..77fcf6c8c5 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticalSummaryValues.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticalSummaryValues.java @@ -17,11 +17,9 @@ package org.apache.commons.math4.legacy.stat.descriptive; import org.apache.commons.math4.core.jdkmath.JdkMath; -import org.apache.commons.numbers.core.Precision; /** - * Value object representing the results of a univariate statistical summary. - * + * Value object representing the results of a univariate statistical summary. */ public class StatisticalSummaryValues implements StatisticalSummary { @@ -120,47 +118,6 @@ public double getVariance() { return variance; } - /** - * Returns true iff object is a - * StatisticalSummaryValues instance and all statistics have - * the same values as this. - * - * @param object the object to test equality against. - * @return true if object equals this - */ - @Override - public boolean equals(Object object) { - if (object == this ) { - return true; - } - if (!(object instanceof StatisticalSummaryValues)) { - return false; - } - StatisticalSummaryValues stat = (StatisticalSummaryValues) object; - return Precision.equalsIncludingNaN(stat.getMax(), getMax()) && - Precision.equalsIncludingNaN(stat.getMean(), getMean()) && - Precision.equalsIncludingNaN(stat.getMin(), getMin()) && - Precision.equalsIncludingNaN(stat.getN(), getN()) && - Precision.equalsIncludingNaN(stat.getSum(), getSum()) && - Precision.equalsIncludingNaN(stat.getVariance(), getVariance()); - } - - /** - * Returns hash code based on values of statistics. - * - * @return hash code - */ - @Override - public int hashCode() { - int result = 31 + Double.hashCode(getMax()); - result = result * 31 + Double.hashCode(getMean()); - result = result * 31 + Double.hashCode(getMin()); - result = result * 31 + Double.hashCode(getN()); - result = result * 31 + Double.hashCode(getSum()); - result = result * 31 + Double.hashCode(getVariance()); - return result; - } - /** * Generates a text report displaying values of statistics. * Each statistic is displayed on a separate line. diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/Statistics.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/Statistics.java new file mode 100644 index 0000000000..9445ea4c37 --- /dev/null +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/Statistics.java @@ -0,0 +1,605 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive; + +import java.util.function.BinaryOperator; +import java.util.function.Supplier; +import org.apache.commons.math4.legacy.core.MathArrays; +import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; +import org.apache.commons.math4.legacy.exception.OutOfRangeException; +import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; +import org.apache.commons.statistics.descriptive.DoubleStatistic; +import org.apache.commons.statistics.descriptive.Quantile; +import org.apache.commons.statistics.descriptive.StatisticResult; +import org.apache.commons.statistics.descriptive.Quantile.EstimationMethod; + +/** + * Utility class delegating computations to Commons Statistics. + */ +final class Statistics { + + /** + * Represents a function that accepts a range of {@code double[]} values and produces a result. + * + * @param the type of the result of the function + */ + @FunctionalInterface + private interface RangeFunction { + /** + * Applies this function to the given arguments. + * + * @param t the function argument + * @param from Inclusive start of the range. + * @param to Exclusive end of the range. + * @return the function result + */ + R apply(double[] t, int from, int to); + } + + /** + * Delegating univariate statistic implementation. + * This is the base class for descriptive statistics computed using an array range. + * + * @param the statistic type + */ + private static class StatImp implements UnivariateStatistic { + /** Statistic function. */ + private final RangeFunction function; + + /** + * Create an instance. + * + * @param function the function + */ + StatImp(RangeFunction function) { + this.function = function; + } + + @Override + public double evaluate(double[] values) { + // This method is not used + throw new IllegalStateException(); + } + + @Override + public double evaluate(double[] values, int begin, int length) { + // Support legacy exception behaviour + MathArrays.verifyValues(values, begin, length); + return function.apply(values, begin, begin + length).getAsDouble(); + } + + @Override + public UnivariateStatistic copy() { + // Return this is safe if the RangeFunction is thread safe + return this; + } + } + + /** + * Delegating univariate statistic implementation that returns NaN for empty arrays. + * + * @param the statistic type + */ + private static class NaNStatImp extends StatImp { + /** + * Create an instance. + * + * @param function the function + */ + NaNStatImp(RangeFunction function) { + super(function); + } + + @Override + public double evaluate(double[] values, int begin, int length) { + // Support legacy behaviour of returning NaN for empty data + final double r = super.evaluate(values, begin, length); + return length == 0 ? Double.NaN : r; + } + } + + /** + * Mean implementation. + */ + static final class Mean extends StatImp { + /** Default instance. */ + private static final Mean INSTANCE = new Mean(); + + /** Create an instance. */ + private Mean() { + super(org.apache.commons.statistics.descriptive.Mean::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static Mean getInstance() { + return INSTANCE; + } + } + + /** + * GeometricMean implementation. + */ + static final class GeometricMean extends StatImp { + /** Default instance. */ + private static final GeometricMean INSTANCE = new GeometricMean(); + + /** Create an instance. */ + private GeometricMean() { + super(org.apache.commons.statistics.descriptive.GeometricMean::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static GeometricMean getInstance() { + return INSTANCE; + } + } + + /** + * Kurtosis implementation. + */ + static final class Kurtosis extends StatImp { + /** Default instance. */ + private static final Kurtosis INSTANCE = new Kurtosis(); + + /** Create an instance. */ + private Kurtosis() { + super(org.apache.commons.statistics.descriptive.Kurtosis::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static Kurtosis getInstance() { + return INSTANCE; + } + } + + /** + * Max implementation. + */ + static final class Max extends NaNStatImp { + /** Default instance. */ + private static final Max INSTANCE = new Max(); + + /** Create an instance. */ + private Max() { + super(org.apache.commons.statistics.descriptive.Max::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static Max getInstance() { + return INSTANCE; + } + } + + /** + * Min implementation. + */ + static final class Min extends NaNStatImp { + /** Default instance. */ + private static final Min INSTANCE = new Min(); + + /** Create an instance. */ + private Min() { + super(org.apache.commons.statistics.descriptive.Min::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static Min getInstance() { + return INSTANCE; + } + } + + /** + * Skewness implementation. + */ + static final class Skewness extends StatImp { + /** Default instance. */ + private static final Skewness INSTANCE = new Skewness(); + + /** Create an instance. */ + private Skewness() { + super(org.apache.commons.statistics.descriptive.Skewness::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static Skewness getInstance() { + return INSTANCE; + } + } + + /** + * Variance implementation. + */ + static final class Variance extends StatImp { + /** Default instance. */ + private static final Variance INSTANCE = new Variance(); + + /** Create an instance. */ + private Variance() { + super(org.apache.commons.statistics.descriptive.Variance::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static Variance getInstance() { + return INSTANCE; + } + } + + /** + * SumOfSquares implementation. + */ + static final class SumOfSquares extends NaNStatImp { + /** Default instance. */ + private static final SumOfSquares INSTANCE = new SumOfSquares(); + + /** Create an instance. */ + private SumOfSquares() { + super(org.apache.commons.statistics.descriptive.SumOfSquares::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static SumOfSquares getInstance() { + return INSTANCE; + } + } + + /** + * Sum implementation. + */ + static final class Sum extends NaNStatImp { + /** Default instance. */ + private static final Sum INSTANCE = new Sum(); + + /** Create an instance. */ + private Sum() { + super(org.apache.commons.statistics.descriptive.Sum::ofRange); + } + + /** + * Gets an instance. + * + * @return instance + */ + static Sum getInstance() { + return INSTANCE; + } + } + + /** + * Percentile implementation. + */ + static final class Percentile implements UnivariateStatistic { + /** Delegate percentile implementation. */ + private static final Quantile QUANTILE = + Quantile.withDefaults().with(EstimationMethod.HF6).withCopy(false); + + /** Probability. */ + private double p; + + /** + * Create an instance. + * + * @param p Probability in [0, 1]. + */ + private Percentile(double p) { + this.p = p; + } + + /** + * Create an instance. + * + * @param percentile Percentile in [0, 100]. + * @return an instance + * @throws OutOfRangeException if the percentile is invalid. + */ + static Percentile create(double percentile) { + return new Percentile(createProbability(percentile)); + } + + /** + * Create the probability from the percentile. + * + * @param percentile Percentile in [0, 100]. + * @return probability in [0, 1] + * @throws OutOfRangeException if the percentile is invalid. + */ + static double createProbability(double percentile) { + if (percentile <= 100 && percentile >= 0) { + return percentile / 100; + } + // NaN or out of range + throw new OutOfRangeException(LocalizedFormats.OUT_OF_RANGE, percentile, 0, 100); + } + + /** + * Sets the quantile (in percent). + * Note: This is named using the CM legacy method name + * setQuantile rather than setPercentile. + * + * @param percentile Percentile in [0, 100]. + * @throws OutOfRangeException if the percentile is invalid. + */ + void setQuantile(double percentile) { + p = createProbability(percentile); + } + + @Override + public double evaluate(double[] values) { + MathArrays.verifyValues(values, 0, 0); + return QUANTILE.evaluate(values, p); + } + + @Override + public double evaluate(double[] values, int begin, int length) { + MathArrays.verifyValues(values, begin, length); + return QUANTILE.evaluateRange(values, begin, begin + length, p); + } + + @Override + public UnivariateStatistic copy() { + return new Percentile(p); + } + } + + /** + * Delegating storeless univariate statistic implementation. + * This is the base class for descriptive statistics computed using a single double value. + * + * @param the statistic type + */ + private static class StorelessStatImp implements StorelessUnivariateStatistic { + /** Statistic factory function. */ + private final Supplier factory; + /** Statistic combine function. */ + private final BinaryOperator combine; + /** Statistic. */ + private R s; + + /** + * Create an instance. + * + * @param factory the factory function + * @param combine the combine function + */ + StorelessStatImp(Supplier factory, BinaryOperator combine) { + this.factory = factory; + this.combine = combine; + s = factory.get(); + } + + @Override + public void increment(double d) { + s.accept(d); + } + + @Override + public void incrementAll(double[] values) throws MathIllegalArgumentException { + // This method is not used + throw new IllegalStateException(); + } + + @Override + public void incrementAll(double[] values, int start, int length) throws MathIllegalArgumentException { + // This method is not used + throw new IllegalStateException(); + } + + @Override + public double getResult() { + return s.getAsDouble(); + } + + @Override + public long getN() { + // This method is not used + throw new IllegalStateException(); + } + + @Override + public void clear() { + s = factory.get(); + } + + @Override + public StorelessUnivariateStatistic copy() { + final StorelessStatImp r = new StorelessStatImp(factory, combine); + r.s = combine.apply(r.s, s); + return r; + } + + @Override + public double evaluate(double[] values) throws MathIllegalArgumentException { + // This method is not used + throw new IllegalStateException(); + } + + @Override + public double evaluate(double[] values, int begin, int length) throws MathIllegalArgumentException { + // This method is not used + throw new IllegalStateException(); + } + } + + /** + * Storeless Sum implementation. + */ + static final class StorelessSum extends StorelessStatImp { + /** Create an instance. */ + private StorelessSum() { + super(org.apache.commons.statistics.descriptive.Sum::create, org.apache.commons.statistics.descriptive.Sum::combine); + } + + /** + * Gets an instance. + * + * @return instance + */ + static StorelessSum create() { + return new StorelessSum(); + } + } + + /** + * Storeless SumOfSquares implementation. + */ + static final class StorelessSumOfSquares extends StorelessStatImp { + /** Create an instance. */ + private StorelessSumOfSquares() { + super(org.apache.commons.statistics.descriptive.SumOfSquares::create, org.apache.commons.statistics.descriptive.SumOfSquares::combine); + } + + /** + * Gets an instance. + * + * @return instance + */ + static StorelessSumOfSquares create() { + return new StorelessSumOfSquares(); + } + } + + /** + * Storeless Min implementation. + */ + static final class StorelessMin extends StorelessStatImp { + /** Create an instance. */ + private StorelessMin() { + super(org.apache.commons.statistics.descriptive.Min::create, org.apache.commons.statistics.descriptive.Min::combine); + } + + /** + * Gets an instance. + * + * @return instance + */ + static StorelessMin create() { + return new StorelessMin(); + } + } + + /** + * Storeless Max implementation. + */ + static final class StorelessMax extends StorelessStatImp { + /** Create an instance. */ + private StorelessMax() { + super(org.apache.commons.statistics.descriptive.Max::create, org.apache.commons.statistics.descriptive.Max::combine); + } + + /** + * Gets an instance. + * + * @return instance + */ + static StorelessMax create() { + return new StorelessMax(); + } + } + + /** + * Storeless SumOfLogs implementation. + */ + static final class StorelessSumOfLogs extends StorelessStatImp { + /** Create an instance. */ + private StorelessSumOfLogs() { + super(org.apache.commons.statistics.descriptive.SumOfLogs::create, org.apache.commons.statistics.descriptive.SumOfLogs::combine); + } + + /** + * Gets an instance. + * + * @return instance + */ + static StorelessSumOfLogs create() { + return new StorelessSumOfLogs(); + } + } + + /** + * Storeless GeometricMean implementation. + */ + static final class StorelessGeometricMean extends StorelessStatImp { + /** Create an instance. */ + private StorelessGeometricMean() { + super(org.apache.commons.statistics.descriptive.GeometricMean::create, org.apache.commons.statistics.descriptive.GeometricMean::combine); + } + + /** + * Gets an instance. + * + * @return instance + */ + static StorelessGeometricMean create() { + return new StorelessGeometricMean(); + } + } + + /** + * Storeless Mean implementation. + */ + static final class StorelessMean extends StorelessStatImp { + /** Create an instance. */ + private StorelessMean() { + super(org.apache.commons.statistics.descriptive.Mean::create, org.apache.commons.statistics.descriptive.Mean::combine); + } + + /** + * Gets an instance. + * + * @return instance + */ + static StorelessMean create() { + return new StorelessMean(); + } + } + + /** No instances. */ + private Statistics() { + // Do nothing + } +} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SummaryStatistics.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SummaryStatistics.java index ff90ddf039..e776d62fc1 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SummaryStatistics.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SummaryStatistics.java @@ -16,20 +16,15 @@ */ package org.apache.commons.math4.legacy.stat.descriptive; +import java.util.EnumSet; +import java.util.Objects; +import java.util.function.DoubleConsumer; +import org.apache.commons.math4.core.jdkmath.JdkMath; import org.apache.commons.math4.legacy.exception.MathIllegalStateException; import org.apache.commons.math4.legacy.exception.NullArgumentException; import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; -import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.SecondMoment; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Max; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Min; -import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares; -import org.apache.commons.math4.core.jdkmath.JdkMath; -import org.apache.commons.numbers.core.Precision; +import org.apache.commons.statistics.descriptive.DoubleStatistics; +import org.apache.commons.statistics.descriptive.Statistic; /** *

@@ -39,13 +34,12 @@ * streams. *

*

- * The {@link StorelessUnivariateStatistic} instances used to maintain summary - * state and compute statistics are configurable via setters. For example, the + * Default implementations can be configured via setters. For example, the * default implementation for the variance can be overridden by calling * {@link #setVarianceImpl(StorelessUnivariateStatistic)}. Actual parameters to * these methods must implement the {@link StorelessUnivariateStatistic} * interface and configuration must be completed before addValue - * is called. No configuration is necessary to use the default, commons-math + * is called. No configuration is necessary to use the default * provided implementations. *

*

@@ -58,61 +52,38 @@ public class SummaryStatistics implements StatisticalSummary { /** count of values that have been added. */ private long n; - /** SecondMoment is used to compute the mean and variance. */ - private SecondMoment secondMoment = new SecondMoment(); - - /** sum of values that have been added. */ - private Sum sum = new Sum(); - - /** sum of the square of each value that has been added. */ - private SumOfSquares sumsq = new SumOfSquares(); - - /** min of values that have been added. */ - private Min min = new Min(); - - /** max of values that have been added. */ - private Max max = new Max(); - - /** sumLog of values that have been added. */ - private SumOfLogs sumLog = new SumOfLogs(); - - /** geoMean of values that have been added. */ - private GeometricMean geoMean = new GeometricMean(sumLog); - - /** mean of values that have been added. */ - private Mean mean = new Mean(secondMoment); - - /** variance of values that have been added. */ - private Variance variance = new Variance(secondMoment); + /** Default statistics. */ + private final EnumSet stats = EnumSet.of(Statistic.SUM, + Statistic.MIN, Statistic.MAX, Statistic.MEAN, + Statistic.VARIANCE); - /** Sum statistic implementation - can be reset by setter. */ - private StorelessUnivariateStatistic sumImpl = sum; + /** Default statistic implementations. */ + private DoubleStatistics values; - /** Sum of squares statistic implementation - can be reset by setter. */ - private StorelessUnivariateStatistic sumsqImpl = sumsq; + /** Consumer of values. */ + private DoubleConsumer action; - /** Minimum statistic implementation - can be reset by setter. */ - private StorelessUnivariateStatistic minImpl = min; + /** Overridden sum statistic implementation - can be reset by setter. */ + private StorelessUnivariateStatistic sumImpl; - /** Maximum statistic implementation - can be reset by setter. */ - private StorelessUnivariateStatistic maxImpl = max; + /** Overridden minimum statistic implementation - can be reset by setter. */ + private StorelessUnivariateStatistic minImpl; - /** Sum of log statistic implementation - can be reset by setter. */ - private StorelessUnivariateStatistic sumLogImpl = sumLog; + /** Overridden maximum statistic implementation - can be reset by setter. */ + private StorelessUnivariateStatistic maxImpl; - /** Geometric mean statistic implementation - can be reset by setter. */ - private StorelessUnivariateStatistic geoMeanImpl = geoMean; + /** Overridden mean statistic implementation - can be reset by setter. */ + private StorelessUnivariateStatistic meanImpl; - /** Mean statistic implementation - can be reset by setter. */ - private StorelessUnivariateStatistic meanImpl = mean; - - /** Variance statistic implementation - can be reset by setter. */ - private StorelessUnivariateStatistic varianceImpl = variance; + /** Overridden variance statistic implementation - can be reset by setter. */ + private StorelessUnivariateStatistic varianceImpl; /** * Construct a SummaryStatistics instance. */ public SummaryStatistics() { + // default implementation + values = DoubleStatistics.of(stats); } /** @@ -140,24 +111,48 @@ public StatisticalSummary getSummary() { * @param value the value to add */ public void addValue(double value) { - sumImpl.increment(value); - sumsqImpl.increment(value); - minImpl.increment(value); - maxImpl.increment(value); - sumLogImpl.increment(value); - secondMoment.increment(value); - // If mean, variance or geomean have been overridden, - // need to increment these - if (meanImpl != mean) { - meanImpl.increment(value); + if (n == 0) { + createAction(); + } + action.accept(value); + n++; + } + + /** + * Creates the consumer of double values. This should be called when + * the implementations have been updated. This should only occur when + * no values have been added, or the object is being copied from another + * source. + */ + private void createAction() { + DoubleConsumer a = null; + if (!stats.isEmpty()) { + values = DoubleStatistics.of(stats); + a = values::accept; } - if (varianceImpl != variance) { - varianceImpl.increment(value); + a = combine(a, sumImpl); + a = combine(a, minImpl); + a = combine(a, maxImpl); + a = combine(a, meanImpl); + a = combine(a, varianceImpl); + action = a; + } + + /** + * Combine the two consumers of double values, either may be null. + * + * @param a Action. + * @param s Statistic. + * @return the consumer + */ + private DoubleConsumer combine(DoubleConsumer a, StorelessUnivariateStatistic s) { + if (s == null) { + return a; } - if (geoMeanImpl != geoMean) { - geoMeanImpl.increment(value); + if (a == null) { + return s::increment; } - n++; + return a.andThen(s::increment); } /** @@ -170,23 +165,26 @@ public long getN() { } /** - * Returns the sum of the values that have been added. - * @return The sum or Double.NaN if no values have been added + * Gets the statistic from the overridden implementation, or from the default implementation. + * + * @param imp Statistics implementation. + * @param s Statistic + * @return the value */ - @Override - public double getSum() { - return sumImpl.getResult(); + private double getStatistic(StorelessUnivariateStatistic imp, Statistic s) { + if (getN() == 0) { + return Double.NaN; + } + return imp != null ? imp.getResult() : values.getAsDouble(s); } /** - * Returns the sum of the squares of the values that have been added. - *

- * Double.NaN is returned if no values have been added. - *

- * @return The sum of squares + * Returns the sum of the values that have been added. + * @return The sum or Double.NaN if no values have been added */ - public double getSumsq() { - return sumsqImpl.getResult(); + @Override + public double getSum() { + return getStatistic(sumImpl, Statistic.SUM); } /** @@ -198,7 +196,7 @@ public double getSumsq() { */ @Override public double getMean() { - return meanImpl.getResult(); + return getStatistic(meanImpl, Statistic.MEAN); } /** @@ -221,46 +219,16 @@ public double getStandardDeviation() { return stdDev; } - /** - * Returns the quadratic mean, a.k.a. - * - * root-mean-square of the available values - * @return The quadratic mean or {@code Double.NaN} if no values - * have been added. - */ - public double getQuadraticMean() { - final long size = getN(); - return size > 0 ? JdkMath.sqrt(getSumsq() / size) : Double.NaN; - } - /** * Returns the (sample) variance of the available values. * - *

This method returns the bias-corrected sample variance (using {@code n - 1} in - * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected - * population variance.

- * *

Double.NaN is returned if no values have been added.

* * @return the variance */ @Override public double getVariance() { - return varianceImpl.getResult(); - } - - /** - * Returns the - * population variance of the values that have been added. - * - *

Double.NaN is returned if no values have been added.

- * - * @return the population variance - */ - public double getPopulationVariance() { - Variance populationVariance = new Variance(secondMoment); - populationVariance.setBiasCorrected(false); - return populationVariance.getResult(); + return getStatistic(varianceImpl, Statistic.VARIANCE); } /** @@ -272,7 +240,7 @@ public double getPopulationVariance() { */ @Override public double getMax() { - return maxImpl.getResult(); + return getStatistic(maxImpl, Statistic.MAX); } /** @@ -284,45 +252,7 @@ public double getMax() { */ @Override public double getMin() { - return minImpl.getResult(); - } - - /** - * Returns the geometric mean of the values that have been added. - *

- * Double.NaN is returned if no values have been added. - *

- * @return the geometric mean - */ - public double getGeometricMean() { - return geoMeanImpl.getResult(); - } - - /** - * Returns the sum of the logs of the values that have been added. - *

- * Double.NaN is returned if no values have been added. - *

- * @return the sum of logs - * @since 1.2 - */ - public double getSumOfLogs() { - return sumLogImpl.getResult(); - } - - /** - * Returns a statistic related to the Second Central Moment. Specifically, - * what is returned is the sum of squared deviations from the sample mean - * among the values that have been added. - *

- * Returns Double.NaN if no data values have been added and - * returns 0 if there is just one value in the data set. - *

- * @return second central moment statistic - * @since 2.0 - */ - public double getSecondMoment() { - return secondMoment.getResult(); + return getStatistic(minImpl, Statistic.MIN); } /** @@ -341,15 +271,9 @@ public String toString() { outBuffer.append("max: ").append(getMax()).append(endl); outBuffer.append("sum: ").append(getSum()).append(endl); outBuffer.append("mean: ").append(getMean()).append(endl); - outBuffer.append("geometric mean: ").append(getGeometricMean()) - .append(endl); outBuffer.append("variance: ").append(getVariance()).append(endl); - outBuffer.append("population variance: ").append(getPopulationVariance()).append(endl); - outBuffer.append("second moment: ").append(getSecondMoment()).append(endl); - outBuffer.append("sum of squares: ").append(getSumsq()).append(endl); outBuffer.append("standard deviation: ").append(getStandardDeviation()) .append(endl); - outBuffer.append("sum of logs: ").append(getSumOfLogs()).append(endl); return outBuffer.toString(); } @@ -358,68 +282,35 @@ public String toString() { */ public void clear() { this.n = 0; - minImpl.clear(); - maxImpl.clear(); - sumImpl.clear(); - sumLogImpl.clear(); - sumsqImpl.clear(); - geoMeanImpl.clear(); - secondMoment.clear(); - if (meanImpl != mean) { - meanImpl.clear(); - } - if (varianceImpl != variance) { - varianceImpl.clear(); + // No clear method for default statistics. Do not set to null as this invalidates + // default getters when empty so recreate. + if (!stats.isEmpty()) { + values = DoubleStatistics.of(stats); } + action = null; + clear(sumImpl); + clear(minImpl); + clear(maxImpl); + clear(meanImpl); + clear(varianceImpl); } /** - * Returns true iff object is a - * SummaryStatistics instance and all statistics have the - * same values as this. - * @param object the object to test equality against. - * @return true if object equals this + * Clear the statistic if not null. + * + * @param s Statistic. */ - @Override - public boolean equals(Object object) { - if (object == this) { - return true; - } - if (!(object instanceof SummaryStatistics)) { - return false; + private static void clear(StorelessUnivariateStatistic s) { + if (s != null) { + s.clear(); } - SummaryStatistics stat = (SummaryStatistics)object; - return Precision.equalsIncludingNaN(stat.getGeometricMean(), getGeometricMean()) && - Precision.equalsIncludingNaN(stat.getMax(), getMax()) && - Precision.equalsIncludingNaN(stat.getMean(), getMean()) && - Precision.equalsIncludingNaN(stat.getMin(), getMin()) && - Precision.equalsIncludingNaN(stat.getN(), getN()) && - Precision.equalsIncludingNaN(stat.getSum(), getSum()) && - Precision.equalsIncludingNaN(stat.getSumsq(), getSumsq()) && - Precision.equalsIncludingNaN(stat.getVariance(), getVariance()); - } - - /** - * Returns hash code based on values of statistics. - * @return hash code - */ - @Override - public int hashCode() { - int result = 31 + Double.hashCode(getGeometricMean()); - result = result * 31 + Double.hashCode(getGeometricMean()); - result = result * 31 + Double.hashCode(getMax()); - result = result * 31 + Double.hashCode(getMean()); - result = result * 31 + Double.hashCode(getMin()); - result = result * 31 + Double.hashCode(getN()); - result = result * 31 + Double.hashCode(getSum()); - result = result * 31 + Double.hashCode(getSumsq()); - result = result * 31 + Double.hashCode(getVariance()); - return result; } // Getters and setters for statistics implementations + /** * Returns the currently configured Sum implementation. + * This will be null if using the default implementation. * @return the StorelessUnivariateStatistic implementing the sum * @since 1.2 */ @@ -444,42 +335,12 @@ public StorelessUnivariateStatistic getSumImpl() { */ public void setSumImpl(StorelessUnivariateStatistic sumImpl) throws MathIllegalStateException { - checkEmpty(); - this.sumImpl = sumImpl; - } - - /** - * Returns the currently configured sum of squares implementation. - * @return the StorelessUnivariateStatistic implementing the sum of squares - * @since 1.2 - */ - public StorelessUnivariateStatistic getSumsqImpl() { - return sumsqImpl; - } - - /** - *

- * Sets the implementation for the sum of squares. - *

- *

- * This method cannot be activated after data has been added - i.e., - * after {@link #addValue(double) addValue} has been used to add data. - * If it is activated after data has been added, an IllegalStateException - * will be thrown. - *

- * @param sumsqImpl the StorelessUnivariateStatistic instance to use for - * computing the sum of squares - * @throws MathIllegalStateException if data has already been added (i.e if n > 0) - * @since 1.2 - */ - public void setSumsqImpl(StorelessUnivariateStatistic sumsqImpl) - throws MathIllegalStateException { - checkEmpty(); - this.sumsqImpl = sumsqImpl; + this.sumImpl = requireImplementation(sumImpl, Statistic.SUM); } /** * Returns the currently configured minimum implementation. + * This will be null if using the default implementation. * @return the StorelessUnivariateStatistic implementing the minimum * @since 1.2 */ @@ -504,12 +365,12 @@ public StorelessUnivariateStatistic getMinImpl() { */ public void setMinImpl(StorelessUnivariateStatistic minImpl) throws MathIllegalStateException { - checkEmpty(); - this.minImpl = minImpl; + this.minImpl = requireImplementation(minImpl, Statistic.MIN); } /** * Returns the currently configured maximum implementation. + * This will be null if using the default implementation. * @return the StorelessUnivariateStatistic implementing the maximum * @since 1.2 */ @@ -534,73 +395,12 @@ public StorelessUnivariateStatistic getMaxImpl() { */ public void setMaxImpl(StorelessUnivariateStatistic maxImpl) throws MathIllegalStateException { - checkEmpty(); - this.maxImpl = maxImpl; - } - - /** - * Returns the currently configured sum of logs implementation. - * @return the StorelessUnivariateStatistic implementing the log sum - * @since 1.2 - */ - public StorelessUnivariateStatistic getSumLogImpl() { - return sumLogImpl; - } - - /** - *

- * Sets the implementation for the sum of logs. - *

- *

- * This method cannot be activated after data has been added - i.e., - * after {@link #addValue(double) addValue} has been used to add data. - * If it is activated after data has been added, an IllegalStateException - * will be thrown. - *

- * @param sumLogImpl the StorelessUnivariateStatistic instance to use for - * computing the log sum - * @throws MathIllegalStateException if data has already been added (i.e if n > 0) - * @since 1.2 - */ - public void setSumLogImpl(StorelessUnivariateStatistic sumLogImpl) - throws MathIllegalStateException { - checkEmpty(); - this.sumLogImpl = sumLogImpl; - geoMean.setSumLogImpl(sumLogImpl); - } - - /** - * Returns the currently configured geometric mean implementation. - * @return the StorelessUnivariateStatistic implementing the geometric mean - * @since 1.2 - */ - public StorelessUnivariateStatistic getGeoMeanImpl() { - return geoMeanImpl; - } - - /** - *

- * Sets the implementation for the geometric mean. - *

- *

- * This method cannot be activated after data has been added - i.e., - * after {@link #addValue(double) addValue} has been used to add data. - * If it is activated after data has been added, an IllegalStateException - * will be thrown. - *

- * @param geoMeanImpl the StorelessUnivariateStatistic instance to use for - * computing the geometric mean - * @throws MathIllegalStateException if data has already been added (i.e if n > 0) - * @since 1.2 - */ - public void setGeoMeanImpl(StorelessUnivariateStatistic geoMeanImpl) - throws MathIllegalStateException { - checkEmpty(); - this.geoMeanImpl = geoMeanImpl; + this.maxImpl = requireImplementation(maxImpl, Statistic.MAX); } /** * Returns the currently configured mean implementation. + * This will be null if using the default implementation. * @return the StorelessUnivariateStatistic implementing the mean * @since 1.2 */ @@ -625,12 +425,12 @@ public StorelessUnivariateStatistic getMeanImpl() { */ public void setMeanImpl(StorelessUnivariateStatistic meanImpl) throws MathIllegalStateException { - checkEmpty(); - this.meanImpl = meanImpl; + this.meanImpl = requireImplementation(meanImpl, Statistic.MEAN); } /** * Returns the currently configured variance implementation. + * This will be null if using the default implementation. * @return the StorelessUnivariateStatistic implementing the variance * @since 1.2 */ @@ -655,19 +455,28 @@ public StorelessUnivariateStatistic getVarianceImpl() { */ public void setVarianceImpl(StorelessUnivariateStatistic varianceImpl) throws MathIllegalStateException { - checkEmpty(); - this.varianceImpl = varianceImpl; + this.varianceImpl = requireImplementation(varianceImpl, Statistic.VARIANCE); } /** - * Throws IllegalStateException if n > 0. + * Checks the implementation can be set. + * Throws {@link IllegalStateException} if {@code n > 0} or a {@link NullPointerException} + * if the implementation is null. + * + * @param imp Implementation. + * @param s Statistic to override. + * @return the implementation * @throws MathIllegalStateException if data has been added */ - private void checkEmpty() throws MathIllegalStateException { + private StorelessUnivariateStatistic requireImplementation(StorelessUnivariateStatistic imp, Statistic s) { if (n > 0) { throw new MathIllegalStateException( LocalizedFormats.VALUES_ADDED_BEFORE_CONFIGURING_STATISTIC, n); } + Objects.requireNonNull(imp, () -> "implementation for " + s); + // Remove the default implementation + stats.remove(s); + return imp; } /** @@ -694,72 +503,28 @@ public static void copy(SummaryStatistics source, SummaryStatistics dest) throws NullArgumentException { NullArgumentException.check(source); NullArgumentException.check(dest); - dest.maxImpl = source.maxImpl.copy(); - dest.minImpl = source.minImpl.copy(); - dest.sumImpl = source.sumImpl.copy(); - dest.sumLogImpl = source.sumLogImpl.copy(); - dest.sumsqImpl = source.sumsqImpl.copy(); - dest.secondMoment = source.secondMoment.copy(); dest.n = source.n; - - // Keep commons-math supplied statistics with embedded moments in synch - if (source.getVarianceImpl() instanceof Variance) { - dest.varianceImpl = new Variance(dest.secondMoment); - } else { - dest.varianceImpl = source.varianceImpl.copy(); - } - if (source.meanImpl instanceof Mean) { - dest.meanImpl = new Mean(dest.secondMoment); - } else { - dest.meanImpl = source.meanImpl.copy(); - } - if (source.getGeoMeanImpl() instanceof GeometricMean) { - dest.geoMeanImpl = new GeometricMean((SumOfLogs) dest.sumLogImpl); - } else { - dest.geoMeanImpl = source.geoMeanImpl.copy(); + // Set up implementations + dest.stats.retainAll(source.stats); + dest.sumImpl = copy(source.sumImpl); + dest.minImpl = copy(source.minImpl); + dest.maxImpl = copy(source.maxImpl); + dest.meanImpl = copy(source.meanImpl); + dest.varianceImpl = copy(source.varianceImpl); + dest.createAction(); + // populate default implementations + if (!dest.stats.isEmpty()) { + dest.values.combine(source.values); } + } - // Make sure that if stat == statImpl in source, same - // holds in dest; otherwise copy stat - if (source.geoMean == source.geoMeanImpl) { - dest.geoMean = (GeometricMean) dest.geoMeanImpl; - } else { - GeometricMean.copy(source.geoMean, dest.geoMean); - } - if (source.max == source.maxImpl) { - dest.max = (Max) dest.maxImpl; - } else { - Max.copy(source.max, dest.max); - } - if (source.mean == source.meanImpl) { - dest.mean = (Mean) dest.meanImpl; - } else { - Mean.copy(source.mean, dest.mean); - } - if (source.min == source.minImpl) { - dest.min = (Min) dest.minImpl; - } else { - Min.copy(source.min, dest.min); - } - if (source.sum == source.sumImpl) { - dest.sum = (Sum) dest.sumImpl; - } else { - Sum.copy(source.sum, dest.sum); - } - if (source.variance == source.varianceImpl) { - dest.variance = (Variance) dest.varianceImpl; - } else { - Variance.copy(source.variance, dest.variance); - } - if (source.sumLog == source.sumLogImpl) { - dest.sumLog = (SumOfLogs) dest.sumLogImpl; - } else { - SumOfLogs.copy(source.sumLog, dest.sumLog); - } - if (source.sumsq == source.sumsqImpl) { - dest.sumsq = (SumOfSquares) dest.sumsqImpl; - } else { - SumOfSquares.copy(source.sumsq, dest.sumsq); - } + /** + * Copy the statistic if not null. + * + * @param s Statistic. + * @return the statistic (or null) + */ + private static StorelessUnivariateStatistic copy(StorelessUnivariateStatistic s) { + return s != null ? s.copy() : null; } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java index 49394ce153..760e6b155b 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SynchronizedMultivariateSummaryStatistics.java @@ -156,22 +156,6 @@ public synchronized void clear() { super.clear(); } - /** - * {@inheritDoc} - */ - @Override - public synchronized boolean equals(Object object) { - return super.equals(object); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized int hashCode() { - return super.hashCode(); - } - /** * {@inheritDoc} */ diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SynchronizedSummaryStatistics.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SynchronizedSummaryStatistics.java index 827e222688..c1eb79c5e8 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SynchronizedSummaryStatistics.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/SynchronizedSummaryStatistics.java @@ -82,14 +82,6 @@ public synchronized double getSum() { return super.getSum(); } - /** - * {@inheritDoc} - */ - @Override - public synchronized double getSumsq() { - return super.getSumsq(); - } - /** * {@inheritDoc} */ @@ -106,14 +98,6 @@ public synchronized double getStandardDeviation() { return super.getStandardDeviation(); } - /** - * {@inheritDoc} - */ - @Override - public synchronized double getQuadraticMean() { - return super.getQuadraticMean(); - } - /** * {@inheritDoc} */ @@ -122,14 +106,6 @@ public synchronized double getVariance() { return super.getVariance(); } - /** - * {@inheritDoc} - */ - @Override - public synchronized double getPopulationVariance() { - return super.getPopulationVariance(); - } - /** * {@inheritDoc} */ @@ -146,14 +122,6 @@ public synchronized double getMin() { return super.getMin(); } - /** - * {@inheritDoc} - */ - @Override - public synchronized double getGeometricMean() { - return super.getGeometricMean(); - } - /** * {@inheritDoc} */ @@ -170,22 +138,6 @@ public synchronized void clear() { super.clear(); } - /** - * {@inheritDoc} - */ - @Override - public synchronized boolean equals(Object object) { - return super.equals(object); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized int hashCode() { - return super.hashCode(); - } - /** * {@inheritDoc} */ @@ -203,23 +155,6 @@ public synchronized void setSumImpl(StorelessUnivariateStatistic sumImpl) super.setSumImpl(sumImpl); } - /** - * {@inheritDoc} - */ - @Override - public synchronized StorelessUnivariateStatistic getSumsqImpl() { - return super.getSumsqImpl(); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized void setSumsqImpl(StorelessUnivariateStatistic sumsqImpl) - throws MathIllegalStateException { - super.setSumsqImpl(sumsqImpl); - } - /** * {@inheritDoc} */ @@ -254,40 +189,6 @@ public synchronized void setMaxImpl(StorelessUnivariateStatistic maxImpl) super.setMaxImpl(maxImpl); } - /** - * {@inheritDoc} - */ - @Override - public synchronized StorelessUnivariateStatistic getSumLogImpl() { - return super.getSumLogImpl(); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized void setSumLogImpl(StorelessUnivariateStatistic sumLogImpl) - throws MathIllegalStateException { - super.setSumLogImpl(sumLogImpl); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized StorelessUnivariateStatistic getGeoMeanImpl() { - return super.getGeoMeanImpl(); - } - - /** - * {@inheritDoc} - */ - @Override - public synchronized void setGeoMeanImpl(StorelessUnivariateStatistic geoMeanImpl) - throws MathIllegalStateException { - super.setGeoMeanImpl(geoMeanImpl); - } - /** * {@inheritDoc} */ diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FirstMoment.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FirstMoment.java deleted file mode 100644 index f97e7c9d33..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FirstMoment.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; - -/** - * Computes the first moment (arithmetic mean). Uses the definitional formula: - *

- * mean = sum(x_i) / n

- *

- * where n is the number of observations.

- *

- * To limit numeric errors, the value of the statistic is computed using the - * following recursive updating algorithm:

- *
    - *
  1. Initialize m = the first value
  2. - *
  3. For each additional value, update using
    - * m = m + (new value - m) / (number of observations)
  4. - *
- *

- * Returns Double.NaN if the dataset is empty. Note that - * Double.NaN may also be returned if the input includes NaN and / or infinite - * values.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -class FirstMoment extends AbstractStorelessUnivariateStatistic { - /** Count of values that have been added. */ - protected long n; - - /** First moment of values that have been added. */ - protected double m1; - - /** - * Deviation of most recently added value from previous first moment. - * Retained to prevent repeated computation in higher order moments. - */ - protected double dev; - - /** - * Deviation of most recently added value from previous first moment, - * normalized by previous sample size. Retained to prevent repeated - * computation in higher order moments - */ - protected double nDev; - - /** - * Create a FirstMoment instance. - */ - FirstMoment() { - n = 0; - m1 = Double.NaN; - dev = Double.NaN; - nDev = Double.NaN; - } - - /** - * Copy constructor, creates a new {@code FirstMoment} identical. - * to the {@code original} - * - * @param original the {@code FirstMoment} instance to copy - * @throws NullArgumentException if original is null - */ - FirstMoment(FirstMoment original) throws NullArgumentException { - super(); - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - if (n == 0) { - m1 = 0.0; - } - n++; - double n0 = n; - dev = d - m1; - nDev = dev / n0; - m1 += nDev; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - m1 = Double.NaN; - n = 0; - dev = Double.NaN; - nDev = Double.NaN; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return m1; - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return n; - } - - /** - * {@inheritDoc} - */ - @Override - public FirstMoment copy() { - FirstMoment result = new FirstMoment(); - // No try-catch or advertised exception because args are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source FirstMoment to copy - * @param dest FirstMoment to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(FirstMoment source, FirstMoment dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.n = source.n; - dest.m1 = source.m1; - dest.dev = source.dev; - dest.nDev = source.nDev; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FourthMoment.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FourthMoment.java deleted file mode 100644 index 5a47fd49b4..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FourthMoment.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.NullArgumentException; - -/** - * Computes a statistic related to the Fourth Central Moment. Specifically, - * what is computed is the sum of - *

- * (x_i - xbar) ^ 4,

- *

- * where the x_i are the - * sample observations and xbar is the sample mean.

- *

- * The following recursive updating formula is used:

- *

- * Let

- * Then - *

- * new value = old value - 4 * (dev/n) * m3 + 6 * (dev/n)^2 * m2 +
- * [n^2 - 3 * (n-1)] * dev^4 * (n-1) / n^3

- *

- * Returns Double.NaN if no data values have been added and - * returns 0 if there is just one value in the data set. Note that - * Double.NaN may also be returned if the input includes NaN and / or infinite - * values.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -class FourthMoment extends ThirdMoment { - /** fourth moment of values that have been added. */ - private double m4; - - /** - * Create a FourthMoment instance. - */ - FourthMoment() { - super(); - m4 = Double.NaN; - } - - /** - * Copy constructor, creates a new {@code FourthMoment} identical - * to the {@code original}. - * - * @param original the {@code FourthMoment} instance to copy - * @throws NullArgumentException if original is null - */ - FourthMoment(FourthMoment original) throws NullArgumentException { - super(); - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - if (n < 1) { - m4 = 0.0; - m3 = 0.0; - m2 = 0.0; - m1 = 0.0; - } - - double prevM3 = m3; - double prevM2 = m2; - - super.increment(d); - - double n0 = n; - - m4 = m4 - 4.0 * nDev * prevM3 + 6.0 * nDevSq * prevM2 + - ((n0 * n0) - 3 * (n0 -1)) * (nDevSq * nDevSq * (n0 - 1) * n0); - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return m4; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - super.clear(); - m4 = Double.NaN; - } - - /** - * {@inheritDoc} - */ - @Override - public FourthMoment copy() { - FourthMoment result = new FourthMoment(); - // No try-catch or advertised exception because args are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source FourthMoment to copy - * @param dest FourthMoment to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(FourthMoment source, FourthMoment dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - ThirdMoment.copy(source, dest); - dest.m4 = source.m4; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/GeometricMean.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/GeometricMean.java deleted file mode 100644 index 9fa60a6ace..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/GeometricMean.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.MathIllegalStateException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatistic; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs; -import org.apache.commons.math4.core.jdkmath.JdkMath; - -/** - * Returns the - * geometric mean of the available values. - *

- * Uses a {@link SumOfLogs} instance to compute sum of logs and returns - * exp( 1/n (sum of logs) ). Therefore,

- * - *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class GeometricMean extends AbstractStorelessUnivariateStatistic { - /** Wrapped SumOfLogs instance. */ - private StorelessUnivariateStatistic sumOfLogs; - - /** - * Create a GeometricMean instance. - */ - public GeometricMean() { - sumOfLogs = new SumOfLogs(); - } - - /** - * Copy constructor, creates a new {@code GeometricMean} identical - * to the {@code original}. - * - * @param original the {@code GeometricMean} instance to copy - * @throws NullArgumentException if original is null - */ - public GeometricMean(GeometricMean original) throws NullArgumentException { - super(); - copy(original, this); - } - - /** - * Create a GeometricMean instance using the given SumOfLogs instance. - * @param sumOfLogs sum of logs instance to use for computation. - */ - public GeometricMean(SumOfLogs sumOfLogs) { - this.sumOfLogs = sumOfLogs; - } - - /** - * {@inheritDoc} - */ - @Override - public GeometricMean copy() { - GeometricMean result = new GeometricMean(); - // no try-catch or advertised exception because args guaranteed non-null - copy(this, result); - return result; - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - sumOfLogs.increment(d); - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - if (sumOfLogs.getN() > 0) { - return JdkMath.exp(sumOfLogs.getResult() / sumOfLogs.getN()); - } else { - return Double.NaN; - } - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - sumOfLogs.clear(); - } - - /** - * Returns the geometric mean of the entries in the specified portion - * of the input array. - *

- * See {@link GeometricMean} for details on the computing algorithm.

- *

- * Throws IllegalArgumentException if the array is null.

- * - * @param values input array containing the values - * @param begin first array element to include - * @param length the number of elements to include - * @return the geometric mean or Double.NaN if length = 0 or - * any of the values are <= 0. - * @throws MathIllegalArgumentException if the input array is null or the array - * index parameters are not valid - */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - return JdkMath.exp(sumOfLogs.evaluate(values, begin, length) / length); - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return sumOfLogs.getN(); - } - - /** - *

Sets the implementation for the sum of logs.

- *

This method must be activated before any data has been added - i.e., - * before {@link #increment(double) increment} has been used to add data; - * otherwise an IllegalStateException will be thrown.

- * - * @param sumLogImpl the StorelessUnivariateStatistic instance to use - * for computing the log sum - * @throws MathIllegalStateException if data has already been added - * (i.e if n > 0) - */ - public void setSumLogImpl(StorelessUnivariateStatistic sumLogImpl) - throws MathIllegalStateException { - checkEmpty(); - this.sumOfLogs = sumLogImpl; - } - - /** - * Returns the currently configured sum of logs implementation. - * - * @return the StorelessUnivariateStatistic implementing the log sum - */ - public StorelessUnivariateStatistic getSumLogImpl() { - return sumOfLogs; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source GeometricMean to copy - * @param dest GeometricMean to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(GeometricMean source, GeometricMean dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.sumOfLogs = source.sumOfLogs.copy(); - } - - /** - * Throws MathIllegalStateException if n > 0. - * @throws MathIllegalStateException if data has been added to this statistic - */ - private void checkEmpty() throws MathIllegalStateException { - if (getN() > 0) { - throw new MathIllegalStateException( - LocalizedFormats.VALUES_ADDED_BEFORE_CONFIGURING_STATISTIC, - getN()); - } - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Kurtosis.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Kurtosis.java deleted file mode 100644 index 29cf179d1f..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Kurtosis.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.core.jdkmath.JdkMath; -import org.apache.commons.math4.legacy.core.MathArrays; - - -/** - * Computes the Kurtosis of the available values. - *

- * We use the following (unbiased) formula to define kurtosis:

- *

- * kurtosis = { [n(n+1) / (n -1)(n - 2)(n-3)] sum[(x_i - mean)^4] / std^4 } - [3(n-1)^2 / (n-2)(n-3)] - *

- * where n is the number of values, mean is the {@link Mean} and std is the - * {@link StandardDeviation}

- *

- * Note that this statistic is undefined for {@code n < 4}. Double.Nan - * is returned when there is not sufficient data to compute the statistic. - * Note that Double.NaN may also be returned if the input includes NaN - * and / or infinite values.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class Kurtosis extends AbstractStorelessUnivariateStatistic { - /**Fourth Moment on which this statistic is based. */ - protected FourthMoment moment; - - /** - * Determines whether or not this statistic can be incremented or cleared. - *

- * Statistics based on (constructed from) external moments cannot - * be incremented or cleared.

- */ - protected boolean incMoment; - - /** - * Construct a Kurtosis. - */ - public Kurtosis() { - incMoment = true; - moment = new FourthMoment(); - } - - /** - * Construct a Kurtosis from an external moment. - * - * @param m4 external Moment - */ - public Kurtosis(final FourthMoment m4) { - incMoment = false; - this.moment = m4; - } - - /** - * Copy constructor, creates a new {@code Kurtosis} identical - * to the {@code original}. - * - * @param original the {@code Kurtosis} instance to copy - * @throws NullArgumentException if original is null - */ - public Kurtosis(Kurtosis original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - *

Note that when {@link #Kurtosis(FourthMoment)} is used to - * create a Variance, this method does nothing. In that case, the - * FourthMoment should be incremented directly.

- */ - @Override - public void increment(final double d) { - if (incMoment) { - moment.increment(d); - } - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - double kurtosis = Double.NaN; - if (moment.getN() > 3) { - double variance = moment.m2 / (moment.n - 1); - if (moment.n <= 3 || variance < 10E-20) { - kurtosis = 0.0; - } else { - double n = moment.n; - kurtosis = - (n * (n + 1) * moment.getResult() - - 3 * moment.m2 * moment.m2 * (n - 1)) / - ((n - 1) * (n -2) * (n -3) * variance * variance); - } - } - return kurtosis; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - if (incMoment) { - moment.clear(); - } - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return moment.getN(); - } - - /* UnivariateStatistic Approach */ - - /** - * Returns the kurtosis of the entries in the specified portion of the - * input array. - *

- * See {@link Kurtosis} for details on the computing algorithm.

- *

- * Throws IllegalArgumentException if the array is null.

- * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the kurtosis of the values or Double.NaN if length is less than 4 - * @throws MathIllegalArgumentException if the input array is null or the array - * index parameters are not valid - */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - - // Initialize the kurtosis - double kurt = Double.NaN; - - if (MathArrays.verifyValues(values, begin, length) && length > 3) { - // Compute the mean and standard deviation - Variance variance = new Variance(); - variance.incrementAll(values, begin, length); - double mean = variance.moment.m1; - double stdDev = JdkMath.sqrt(variance.getResult()); - - // Sum the ^4 of the distance from the mean divided by the - // standard deviation - double accum3 = 0.0; - for (int i = begin; i < begin + length; i++) { - accum3 += JdkMath.pow(values[i] - mean, 4.0); - } - accum3 /= JdkMath.pow(stdDev, 4.0d); - - // Get N - double n0 = length; - - double coefficientOne = - (n0 * (n0 + 1)) / ((n0 - 1) * (n0 - 2) * (n0 - 3)); - double termTwo = - (3 * JdkMath.pow(n0 - 1, 2.0)) / ((n0 - 2) * (n0 - 3)); - - // Calculate kurtosis - kurt = (coefficientOne * accum3) - termTwo; - } - return kurt; - } - - /** - * {@inheritDoc} - */ - @Override - public Kurtosis copy() { - Kurtosis result = new Kurtosis(); - // No try-catch because args are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source Kurtosis to copy - * @param dest Kurtosis to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(Kurtosis source, Kurtosis dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.moment = source.moment.copy(); - dest.incMoment = source.incMoment; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Mean.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Mean.java deleted file mode 100644 index 3fab9af728..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Mean.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation; -import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum; -import org.apache.commons.math4.legacy.core.MathArrays; - -/** - * Computes the arithmetic mean of a set of values. Uses the definitional - * formula: - *

- * mean = sum(x_i) / n - *

- *

where n is the number of observations. - *

- *

When {@link #increment(double)} is used to add data incrementally from a - * stream of (unstored) values, the value of the statistic that - * {@link #getResult()} returns is computed using the following recursive - * updating algorithm:

- *
    - *
  1. Initialize m = the first value
  2. - *
  3. For each additional value, update using
    - * m = m + (new value - m) / (number of observations)
  4. - *
- *

If {@link #evaluate(double[])} is used to compute the mean of an array - * of stored values, a two-pass, corrected algorithm is used, starting with - * the definitional formula computed using the array of stored values and then - * correcting this by adding the mean deviation of the data values from the - * arithmetic mean. See, e.g. "Comparison of Several Algorithms for Computing - * Sample Means and Variances," Robert F. Ling, Journal of the American - * Statistical Association, Vol. 69, No. 348 (Dec., 1974), pp. 859-866.

- *

- * Returns Double.NaN if the dataset is empty. Note that - * Double.NaN may also be returned if the input includes NaN and / or infinite - * values. - *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally. - */ -public class Mean extends AbstractStorelessUnivariateStatistic - implements WeightedEvaluation { - /** First moment on which this statistic is based. */ - protected FirstMoment moment; - - /** - * Determines whether or not this statistic can be incremented or cleared. - *

- * Statistics based on (constructed from) external moments cannot - * be incremented or cleared.

- */ - protected boolean incMoment; - - /** Constructs a Mean. */ - public Mean() { - incMoment = true; - moment = new FirstMoment(); - } - - /** - * Constructs a Mean with an External Moment. - * - * @param m1 the moment - */ - public Mean(final FirstMoment m1) { - this.moment = m1; - incMoment = false; - } - - /** - * Copy constructor, creates a new {@code Mean} identical - * to the {@code original}. - * - * @param original the {@code Mean} instance to copy - * @throws NullArgumentException if original is null - */ - public Mean(Mean original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - *

Note that when {@link #Mean(FirstMoment)} is used to - * create a Mean, this method does nothing. In that case, the - * FirstMoment should be incremented directly.

- */ - @Override - public void increment(final double d) { - if (incMoment) { - moment.increment(d); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - if (incMoment) { - moment.clear(); - } - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return moment.m1; - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return moment.getN(); - } - - /** - * Returns the arithmetic mean of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. - *

- * Throws IllegalArgumentException if the array is null.

- *

- * See {@link Mean} for details on the computing algorithm.

- * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the mean of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - - if (MathArrays.verifyValues(values, begin, length)) { - Sum sum = new Sum(); - double sampleSize = length; - - // Compute initial estimate using definitional formula - double xbar = sum.evaluate(values, begin, length) / sampleSize; - - // Compute correction factor in second pass - double correction = 0; - for (int i = begin; i < begin + length; i++) { - correction += values[i] - xbar; - } - return xbar + (correction/sampleSize); - } - return Double.NaN; - } - - /** - * Returns the weighted arithmetic mean of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. - *

- * Throws IllegalArgumentException if either array is null.

- *

- * See {@link Mean} for details on the computing algorithm. The two-pass algorithm - * described above is used here, with weights applied in computing both the original - * estimate and the correction factor.

- *

- * Throws IllegalArgumentException if any of the following are true: - *

- * - * @param values the input array - * @param weights the weights array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the mean of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the parameters are not valid - * @since 2.1 - */ - @Override - public double evaluate(final double[] values, final double[] weights, - final int begin, final int length) throws MathIllegalArgumentException { - if (MathArrays.verifyValues(values, weights, begin, length)) { - Sum sum = new Sum(); - - // Compute initial estimate using definitional formula - double sumw = sum.evaluate(weights,begin,length); - double xbarw = sum.evaluate(values, weights, begin, length) / sumw; - - // Compute correction factor in second pass - double correction = 0; - for (int i = begin; i < begin + length; i++) { - correction += weights[i] * (values[i] - xbarw); - } - return xbarw + (correction/sumw); - } - return Double.NaN; - } - - /** - * Returns the weighted arithmetic mean of the entries in the input array. - *

- * Throws MathIllegalArgumentException if either array is null.

- *

- * See {@link Mean} for details on the computing algorithm. The two-pass algorithm - * described above is used here, with weights applied in computing both the original - * estimate and the correction factor.

- *

- * Throws MathIllegalArgumentException if any of the following are true: - *

- * - * @param values the input array - * @param weights the weights array - * @return the mean of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the parameters are not valid - * @since 2.1 - */ - @Override - public double evaluate(final double[] values, final double[] weights) - throws MathIllegalArgumentException { - return evaluate(values, weights, 0, values.length); - } - - /** - * {@inheritDoc} - */ - @Override - public Mean copy() { - Mean result = new Mean(); - // No try-catch or advertised exception because args are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source Mean to copy - * @param dest Mean to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(Mean source, Mean dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.incMoment = source.incMoment; - dest.moment = source.moment.copy(); - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SecondMoment.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SecondMoment.java deleted file mode 100644 index 3901a6b4c7..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SecondMoment.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.NullArgumentException; - -/** - * Computes a statistic related to the Second Central Moment. Specifically, - * what is computed is the sum of squared deviations from the sample mean. - *

- * The following recursive updating formula is used:

- *

- * Let

- * Then - *

- * new value = old value + dev^2 * (n -1) / n.

- *

- * Returns Double.NaN if no data values have been added and - * returns 0 if there is just one value in the data set. - * Note that Double.NaN may also be returned if the input includes NaN - * and / or infinite values.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class SecondMoment extends FirstMoment { - /** second moment of values that have been added. */ - protected double m2; - - /** - * Create a SecondMoment instance. - */ - public SecondMoment() { - super(); - m2 = Double.NaN; - } - - /** - * Copy constructor, creates a new {@code SecondMoment} identical - * to the {@code original}. - * - * @param original the {@code SecondMoment} instance to copy - * @throws NullArgumentException if original is null - */ - public SecondMoment(SecondMoment original) throws NullArgumentException { - super(original); - this.m2 = original.m2; - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - if (n < 1) { - m1 = m2 = 0.0; - } - super.increment(d); - m2 += ((double) n - 1) * dev * nDev; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - super.clear(); - m2 = Double.NaN; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return m2; - } - - /** - * {@inheritDoc} - */ - @Override - public SecondMoment copy() { - SecondMoment result = new SecondMoment(); - // no try-catch or advertised NAE because args are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source SecondMoment to copy - * @param dest SecondMoment to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(SecondMoment source, SecondMoment dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - FirstMoment.copy(source, dest); - dest.m2 = source.m2; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SemiVariance.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SemiVariance.java index 0eca2d186d..cb1e646d32 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SemiVariance.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SemiVariance.java @@ -19,6 +19,7 @@ import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; import org.apache.commons.math4.legacy.exception.NullArgumentException; +import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; import org.apache.commons.math4.legacy.stat.descriptive.AbstractUnivariateStatistic; import org.apache.commons.math4.legacy.core.MathArrays; @@ -35,8 +36,7 @@ * *

The cutoff value defaults to the mean, bias correction defaults to true * and the "variance direction" (upside or downside) defaults to downside. The variance direction - * and bias correction may be set using property setters or their values can provided as - * parameters to {@link #evaluate(double[], double, Direction, boolean, int, int)}.

+ * and bias correction may be set using property setters.

* *

If the input array is null, evaluate methods throw * IllegalArgumentException. If the array has length 1, 0 @@ -51,18 +51,6 @@ */ public class SemiVariance extends AbstractUnivariateStatistic { - /** - * The UPSIDE Direction is used to specify that the observations above the - * cutoff point will be used to calculate SemiVariance. - */ - public static final Direction UPSIDE_VARIANCE = Direction.UPSIDE; - - /** - * The DOWNSIDE Direction is used to specify that the observations below. - * the cutoff point will be used to calculate SemiVariance - */ - public static final Direction DOWNSIDE_VARIANCE = Direction.DOWNSIDE; - /** * Determines whether or not bias correction is applied when computing the * value of the statistic. True means that bias is corrected. @@ -79,56 +67,7 @@ public class SemiVariance extends AbstractUnivariateStatistic { * property and default (Downside) varianceDirection property. */ public SemiVariance() { - } - - /** - * Constructs a SemiVariance with the specified biasCorrected - * property and default (Downside) varianceDirection property. - * - * @param biasCorrected setting for bias correction - true means - * bias will be corrected and is equivalent to using the "no arg" - * constructor - */ - public SemiVariance(final boolean biasCorrected) { - this.biasCorrected = biasCorrected; - } - - /** - * Constructs a SemiVariance with the specified Direction property. - * and default (true) biasCorrected property - * - * @param direction setting for the direction of the SemiVariance - * to calculate - */ - public SemiVariance(final Direction direction) { - this.varianceDirection = direction; - } - - /** - * Constructs a SemiVariance with the specified isBiasCorrected - * property and the specified Direction property. - * - * @param corrected setting for bias correction - true means - * bias will be corrected and is equivalent to using the "no arg" - * constructor - * - * @param direction setting for the direction of the SemiVariance - * to calculate - */ - public SemiVariance(final boolean corrected, final Direction direction) { - this.biasCorrected = corrected; - this.varianceDirection = direction; - } - - /** - * Copy constructor, creates a new {@code SemiVariance} identical - * to the {@code original}. - * - * @param original the {@code SemiVariance} instance to copy - * @throws NullArgumentException if original is null - */ - public SemiVariance(final SemiVariance original) throws NullArgumentException { - copy(original, this); + // Do nothing } /** @@ -137,27 +76,11 @@ public SemiVariance(final SemiVariance original) throws NullArgumentException { @Override public SemiVariance copy() { SemiVariance result = new SemiVariance(); - // No try-catch or advertised exception because args are guaranteed non-null - copy(this, result); + result.biasCorrected = biasCorrected; + result.varianceDirection = varianceDirection; return result; } - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source SemiVariance to copy - * @param dest SemiVariance to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(final SemiVariance source, SemiVariance dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.biasCorrected = source.biasCorrected; - dest.varianceDirection = source.varianceDirection; - } - /** *

Returns the {@link SemiVariance} of the designated values against the mean, using * instance properties varianceDirection and biasCorrection.

@@ -175,24 +98,9 @@ public static void copy(final SemiVariance source, SemiVariance dest) @Override public double evaluate(final double[] values, final int start, final int length) throws MathIllegalArgumentException { - double m = (new Mean()).evaluate(values, start, length); - return evaluate(values, m, varianceDirection, biasCorrected, 0, values.length); - } - - /** - * This method calculates {@link SemiVariance} for the entire array against the mean, using - * the current value of the biasCorrection instance property. - * - * @param values the input array - * @param direction the {@link Direction} of the semivariance - * @return the SemiVariance - * @throws MathIllegalArgumentException if values is null - * - */ - public double evaluate(final double[] values, Direction direction) - throws MathIllegalArgumentException { - double m = (new Mean()).evaluate(values); - return evaluate(values, m, direction, biasCorrected, 0, values.length); + MathArrays.verifyValues(values, start, length); + double m = org.apache.commons.statistics.descriptive.Mean.ofRange(values, start, start + length).getAsDouble(); + return compute(values, m, varianceDirection, biasCorrected, start, length); } /** @@ -209,33 +117,38 @@ public double evaluate(final double[] values, Direction direction) */ public double evaluate(final double[] values, final double cutoff) throws MathIllegalArgumentException { - return evaluate(values, cutoff, varianceDirection, biasCorrected, 0, values.length); + if (values == null) { + throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); + } + return compute(values, cutoff, varianceDirection, biasCorrected, 0, values.length); } /** - *

Returns the {@link SemiVariance} of the designated values against the cutoff in the - * given direction, using the current value of the biasCorrection instance property.

+ *

Returns the {@link SemiVariance} of the designated values against the cutoff + * in the given direction with the provided bias correction.

* *

Returns NaN if the array is empty and throws - * MathIllegalArgumentException if the array is null.

+ * IllegalArgumentException if the array is null.

* * @param values the input array * @param cutoff the reference point - * @param direction the {@link Direction} of the semivariance + * @param start index of the first array element to include + * @param length the number of elements to include * @return the SemiVariance - * @throws MathIllegalArgumentException if values is null + * @throws MathIllegalArgumentException if the parameters are not valid + * */ - public double evaluate(final double[] values, final double cutoff, final Direction direction) + public double evaluate(final double[] values, final double cutoff, final int start, final int length) throws MathIllegalArgumentException { - return evaluate(values, cutoff, direction, biasCorrected, 0, values.length); + MathArrays.verifyValues(values, start, length); + return compute(values, cutoff, varianceDirection, biasCorrected, start, length); } /** *

Returns the {@link SemiVariance} of the designated values against the cutoff * in the given direction with the provided bias correction.

* - *

Returns NaN if the array is empty and throws - * IllegalArgumentException if the array is null.

+ *

Returns NaN if the array is empty.

* * @param values the input array * @param cutoff the reference point @@ -244,38 +157,33 @@ public double evaluate(final double[] values, final double cutoff, final Directi * @param start index of the first array element to include * @param length the number of elements to include * @return the SemiVariance - * @throws MathIllegalArgumentException if the parameters are not valid - * */ - public double evaluate (final double[] values, final double cutoff, final Direction direction, - final boolean corrected, final int start, final int length) - throws MathIllegalArgumentException { - - MathArrays.verifyValues(values, start, length); - if (values.length == 0) { + private static double compute(double[] values, double cutoff, Direction direction, + boolean corrected, int start, int length) { + // Arguments must have been validated + if (length == 0) { return Double.NaN; - } else { - if (values.length == 1) { - return 0.0; - } else { - final boolean booleanDirection = direction.getDirection(); - - double dev = 0.0; - double sumsq = 0.0; - for (int i = start; i < length; i++) { - if ((values[i] > cutoff) == booleanDirection) { - dev = values[i] - cutoff; - sumsq += dev * dev; - } - } + } + if (length == 1) { + return 0.0; + } + final boolean booleanDirection = direction.getDirection(); - if (corrected) { - return sumsq / (length - 1.0); - } else { - return sumsq / length; - } + double dev = 0.0; + double sumsq = 0.0; + final int end = start + length; + for (int i = start; i < end; i++) { + if ((values[i] > cutoff) == booleanDirection) { + dev = values[i] - cutoff; + sumsq += dev * dev; } } + + if (corrected) { + return sumsq / (length - 1.0); + } else { + return sumsq / length; + } } /** diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Skewness.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Skewness.java deleted file mode 100644 index 06b839902c..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Skewness.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.core.jdkmath.JdkMath; -import org.apache.commons.math4.legacy.core.MathArrays; - -/** - * Computes the skewness of the available values. - *

- * We use the following (unbiased) formula to define skewness:

- *

- * skewness = [n / (n -1) (n - 2)] sum[(x_i - mean)^3] / std^3

- *

- * where n is the number of values, mean is the {@link Mean} and std is the - * {@link StandardDeviation}

- *

- * Note that this statistic is undefined for {@code n < 3}. Double.Nan - * is returned when there is not sufficient data to compute the statistic. - * Double.NaN may also be returned if the input includes NaN and / or - * infinite values.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class Skewness extends AbstractStorelessUnivariateStatistic { - /** The value below which the variance is considered zero and thus skewness is zero. */ - private static final double ZERO_VARIANCE_THRESHOLD = 10E-20; - - /** Third moment on which this statistic is based. */ - protected ThirdMoment moment; - - /** - * Determines whether or not this statistic can be incremented or cleared. - *

- * Statistics based on (constructed from) external moments cannot - * be incremented or cleared.

- */ - protected boolean incMoment; - - /** - * Constructs a Skewness. - */ - public Skewness() { - incMoment = true; - moment = new ThirdMoment(); - } - - /** - * Constructs a Skewness with an external moment. - * @param m3 external moment - */ - public Skewness(final ThirdMoment m3) { - incMoment = false; - this.moment = m3; - } - - /** - * Copy constructor, creates a new {@code Skewness} identical - * to the {@code original}. - * - * @param original the {@code Skewness} instance to copy - * @throws NullArgumentException if original is null - */ - public Skewness(Skewness original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - *

Note that when {@link #Skewness(ThirdMoment)} is used to - * create a Skewness, this method does nothing. In that case, the - * ThirdMoment should be incremented directly.

- */ - @Override - public void increment(final double d) { - if (incMoment) { - moment.increment(d); - } - } - - /** - * Returns the value of the statistic based on the values that have been added. - *

- * See {@link Skewness} for the definition used in the computation.

- * - * @return the skewness of the available values. - */ - @Override - public double getResult() { - - if (moment.n < 3) { - return Double.NaN; - } - double variance = moment.m2 / (moment.n - 1); - if (variance < ZERO_VARIANCE_THRESHOLD) { - return 0.0d; - } else { - double n0 = moment.getN(); - return (n0 * moment.m3) / - ((n0 - 1) * (n0 -2) * JdkMath.sqrt(variance) * variance); - } - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return moment.getN(); - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - if (incMoment) { - moment.clear(); - } - } - - /** - * Returns the Skewness of the entries in the specified portion of the - * input array. - *

- * See {@link Skewness} for the definition used in the computation.

- *

- * Throws IllegalArgumentException if the array is null.

- * - * @param values the input array - * @param begin the index of the first array element to include - * @param length the number of elements to include - * @return the skewness of the values or Double.NaN if length is less than 3 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - @Override - public double evaluate(final double[] values,final int begin, final int length) - throws MathIllegalArgumentException { - - // Initialize the skewness - double skew = Double.NaN; - - if (MathArrays.verifyValues(values, begin, length) && length > 2 ) { - Mean mean = new Mean(); - // Get the mean and the standard deviation - double m = mean.evaluate(values, begin, length); - - // Calc the std, this is implemented here instead - // of using the standardDeviation method eliminate - // a duplicate pass to get the mean - double accum = 0.0; - double accum2 = 0.0; - for (int i = begin; i < begin + length; i++) { - final double d = values[i] - m; - accum += d * d; - accum2 += d; - } - final double variance = (accum - (accum2 * accum2 / length)) / (length - 1); - if (variance < ZERO_VARIANCE_THRESHOLD) { - skew = 0.0d; - } else { - double accum3 = 0.0; - for (int i = begin; i < begin + length; i++) { - final double d = values[i] - m; - accum3 += d * d * d; - } - accum3 /= variance * JdkMath.sqrt(variance); - - // Get N - double n0 = length; - - // Calculate skewness - skew = (n0 / ((n0 - 1) * (n0 - 2))) * accum3; - } - } - return skew; - } - - /** - * {@inheritDoc} - */ - @Override - public Skewness copy() { - Skewness result = new Skewness(); - // No try-catch or advertised exception because args are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source Skewness to copy - * @param dest Skewness to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(Skewness source, Skewness dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.moment = new ThirdMoment(source.moment.copy()); - dest.incMoment = source.incMoment; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/StandardDeviation.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/StandardDeviation.java deleted file mode 100644 index 3d4a5b7856..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/StandardDeviation.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.core.jdkmath.JdkMath; - -/** - * Computes the sample standard deviation. The standard deviation - * is the positive square root of the variance. This implementation wraps a - * {@link Variance} instance. The isBiasCorrected property of the - * wrapped Variance instance is exposed, so that this class can be used to - * compute both the "sample standard deviation" (the square root of the - * bias-corrected "sample variance") or the "population standard deviation" - * (the square root of the non-bias-corrected "population variance"). See - * {@link Variance} for more information. - *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class StandardDeviation extends AbstractStorelessUnivariateStatistic { - /** Wrapped Variance instance. */ - private Variance variance; - - /** - * Constructs a StandardDeviation. Sets the underlying {@link Variance} - * instance's isBiasCorrected property to true. - */ - public StandardDeviation() { - variance = new Variance(); - } - - /** - * Constructs a StandardDeviation from an external second moment. - * - * @param m2 the external moment - */ - public StandardDeviation(final SecondMoment m2) { - variance = new Variance(m2); - } - - /** - * Copy constructor, creates a new {@code StandardDeviation} identical - * to the {@code original}. - * - * @param original the {@code StandardDeviation} instance to copy - * @throws NullArgumentException if original is null - */ - public StandardDeviation(StandardDeviation original) throws NullArgumentException { - copy(original, this); - } - - /** - * Constructs a StandardDeviation with the specified value for the - * isBiasCorrected property. If this property is set to - * true, the {@link Variance} used in computing results will - * use the bias-corrected, or "sample" formula. See {@link Variance} for - * details. - * - * @param isBiasCorrected whether or not the variance computation will use - * the bias-corrected formula - */ - public StandardDeviation(boolean isBiasCorrected) { - variance = new Variance(isBiasCorrected); - } - - /** - * Constructs a StandardDeviation with the specified value for the - * isBiasCorrected property and the supplied external moment. - * If isBiasCorrected is set to true, the - * {@link Variance} used in computing results will use the bias-corrected, - * or "sample" formula. See {@link Variance} for details. - * - * @param isBiasCorrected whether or not the variance computation will use - * the bias-corrected formula - * @param m2 the external moment - */ - public StandardDeviation(boolean isBiasCorrected, SecondMoment m2) { - variance = new Variance(isBiasCorrected, m2); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - variance.increment(d); - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return variance.getN(); - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return JdkMath.sqrt(variance.getResult()); - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - variance.clear(); - } - - /** - * Returns the Standard Deviation of the entries in the input array, or - * Double.NaN if the array is empty. - *

- * Returns 0 for a single-value (i.e. length = 1) sample.

- *

- * Throws MathIllegalArgumentException if the array is null.

- *

- * Does not change the internal state of the statistic.

- * - * @param values the input array - * @return the standard deviation of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null - */ - @Override - public double evaluate(final double[] values) throws MathIllegalArgumentException { - return JdkMath.sqrt(variance.evaluate(values)); - } - - /** - * Returns the Standard Deviation of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. - *

- * Returns 0 for a single-value (i.e. length = 1) sample.

- *

- * Throws MathIllegalArgumentException if the array is null.

- *

- * Does not change the internal state of the statistic.

- * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the standard deviation of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - return JdkMath.sqrt(variance.evaluate(values, begin, length)); - } - - /** - * Returns the Standard Deviation of the entries in the specified portion of - * the input array, using the precomputed mean value. Returns - * Double.NaN if the designated subarray is empty. - *

- * Returns 0 for a single-value (i.e. length = 1) sample.

- *

- * The formula used assumes that the supplied mean value is the arithmetic - * mean of the sample data, not a known population parameter. This method - * is supplied only to save computation when the mean has already been - * computed.

- *

- * Throws IllegalArgumentException if the array is null.

- *

- * Does not change the internal state of the statistic.

- * - * @param values the input array - * @param mean the precomputed mean value - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the standard deviation of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - public double evaluate(final double[] values, final double mean, - final int begin, final int length) throws MathIllegalArgumentException { - return JdkMath.sqrt(variance.evaluate(values, mean, begin, length)); - } - - /** - * Returns the Standard Deviation of the entries in the input array, using - * the precomputed mean value. Returns - * Double.NaN if the designated subarray is empty. - *

- * Returns 0 for a single-value (i.e. length = 1) sample.

- *

- * The formula used assumes that the supplied mean value is the arithmetic - * mean of the sample data, not a known population parameter. This method - * is supplied only to save computation when the mean has already been - * computed.

- *

- * Throws MathIllegalArgumentException if the array is null.

- *

- * Does not change the internal state of the statistic.

- * - * @param values the input array - * @param mean the precomputed mean value - * @return the standard deviation of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null - */ - public double evaluate(final double[] values, final double mean) - throws MathIllegalArgumentException { - return JdkMath.sqrt(variance.evaluate(values, mean)); - } - - /** - * @return the isBiasCorrected. - */ - public boolean isBiasCorrected() { - return variance.isBiasCorrected(); - } - - /** - * @param isBiasCorrected The isBiasCorrected to set. - */ - public void setBiasCorrected(boolean isBiasCorrected) { - variance.setBiasCorrected(isBiasCorrected); - } - - /** - * {@inheritDoc} - */ - @Override - public StandardDeviation copy() { - StandardDeviation result = new StandardDeviation(); - // No try-catch or advertised exception because args are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source StandardDeviation to copy - * @param dest StandardDeviation to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(StandardDeviation source, StandardDeviation dest) throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.variance = source.variance.copy(); - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/ThirdMoment.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/ThirdMoment.java deleted file mode 100644 index 56ea0c7e94..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/ThirdMoment.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.exception.NullArgumentException; - - -/** - * Computes a statistic related to the Third Central Moment. Specifically, - * what is computed is the sum of cubed deviations from the sample mean. - *

- * The following recursive updating formula is used:

- *

- * Let

- * Then - *

- * new value = old value - 3 * (dev/n) * m2 + (n-1) * (n -2) * (dev^3/n^2)

- *

- * Returns Double.NaN if no data values have been added and - * returns 0 if there is just one value in the data set. - * Note that Double.NaN may also be returned if the input includes NaN - * and / or infinite values.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- * - */ -class ThirdMoment extends SecondMoment { - /** third moment of values that have been added. */ - protected double m3; - - /** - * Square of deviation of most recently added value from previous first - * moment, normalized by previous sample size. Retained to prevent - * repeated computation in higher order moments. nDevSq = nDev * nDev. - */ - protected double nDevSq; - - /** - * Create a FourthMoment instance. - */ - ThirdMoment() { - super(); - m3 = Double.NaN; - nDevSq = Double.NaN; - } - - /** - * Copy constructor, creates a new {@code ThirdMoment} identical - * to the {@code original}. - * - * @param original the {@code ThirdMoment} instance to copy - * @throws NullArgumentException if original is null - */ - ThirdMoment(ThirdMoment original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - if (n < 1) { - m3 = m2 = m1 = 0.0; - } - - double prevM2 = m2; - super.increment(d); - nDevSq = nDev * nDev; - double n0 = n; - m3 = m3 - 3.0 * nDev * prevM2 + (n0 - 1) * (n0 - 2) * nDevSq * dev; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return m3; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - super.clear(); - m3 = Double.NaN; - nDevSq = Double.NaN; - } - - /** - * {@inheritDoc} - */ - @Override - public ThirdMoment copy() { - ThirdMoment result = new ThirdMoment(); - // No try-catch or advertised exception because args are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source ThirdMoment to copy - * @param dest ThirdMoment to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(ThirdMoment source, ThirdMoment dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - SecondMoment.copy(source, dest); - dest.m3 = source.m3; - dest.nDevSq = source.nDevSq; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VectorialCovariance.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VectorialCovariance.java index af8c4be1fe..5948581eb2 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VectorialCovariance.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VectorialCovariance.java @@ -110,38 +110,4 @@ public void clear() { Arrays.fill(sums, 0.0); Arrays.fill(productsSums, 0.0); } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (isBiasCorrected ? 1231 : 1237); - result = prime * result + (int) (n ^ (n >>> 32)); - result = prime * result + Arrays.hashCode(productsSums); - result = prime * result + Arrays.hashCode(sums); - return result; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof VectorialCovariance)) { - return false; - } - VectorialCovariance other = (VectorialCovariance) obj; - if (isBiasCorrected != other.isBiasCorrected) { - return false; - } - if (n != other.n) { - return false; - } - if (!Arrays.equals(productsSums, other.productsSums)) { - return false; - } - return Arrays.equals(sums, other.sums); - } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VectorialMean.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VectorialMean.java index af9e161872..1409973d0c 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VectorialMean.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VectorialMean.java @@ -16,8 +16,6 @@ */ package org.apache.commons.math4.legacy.stat.descriptive.moment; -import java.util.Arrays; - import org.apache.commons.math4.legacy.exception.DimensionMismatchException; /** @@ -26,15 +24,17 @@ */ public class VectorialMean { /** Means for each component. */ - private final Mean[] means; + private final org.apache.commons.statistics.descriptive.Mean[] means; + /** Sample count. */ + private long n; /** Constructs a VectorialMean. * @param dimension vectors dimension */ public VectorialMean(int dimension) { - means = new Mean[dimension]; + means = new org.apache.commons.statistics.descriptive.Mean[dimension]; for (int i = 0; i < dimension; ++i) { - means[i] = new Mean(); + means[i] = org.apache.commons.statistics.descriptive.Mean.create(); } } @@ -48,8 +48,9 @@ public void increment(double[] v) throws DimensionMismatchException { throw new DimensionMismatchException(v.length, means.length); } for (int i = 0; i < v.length; ++i) { - means[i].increment(v[i]); + means[i].accept(v[i]); } + n++; } /** @@ -59,7 +60,7 @@ public void increment(double[] v) throws DimensionMismatchException { public double[] getResult() { double[] result = new double[means.length]; for (int i = 0; i < result.length; ++i) { - result[i] = means[i].getResult(); + result[i] = means[i].getAsDouble(); } return result; } @@ -69,28 +70,6 @@ public double[] getResult() { * @return number of vectors in the sample */ public long getN() { - return (means.length == 0) ? 0 : means[0].getN(); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Arrays.hashCode(means); - return result; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof VectorialMean)) { - return false; - } - VectorialMean other = (VectorialMean) obj; - return Arrays.equals(means, other.means); + return (means.length == 0) ? 0 : n; } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedMean.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedMean.java new file mode 100644 index 0000000000..bea1ff5840 --- /dev/null +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedMean.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; + +import org.apache.commons.math4.legacy.core.MathArrays; +import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; +import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation; + +/** + * Computes the weighted mean of a set of values. Uses the formula: + *

+ * mean = sum(w_i * x_i) / sum(w_i) + *

+ *

where w_i is the weight for observation x_i. + *

+ *

If used to compute the mean of an array + * of stored values, a two-pass, corrected algorithm is used, starting with + * the definitional formula computed using the array of stored values and then + * correcting this by adding the mean deviation of the data values from the + * arithmetic mean. See, e.g. "Comparison of Several Algorithms for Computing + * Sample Means and Variances," Robert F. Ling, Journal of the American + * Statistical Association, Vol. 69, No. 348 (Dec., 1974), pp. 859-866.

+ *

+ * Returns Double.NaN if the dataset is empty. Note that + * Double.NaN may also be returned if the input includes NaN and / or infinite + * values. + *

+ */ +public final class WeightedMean implements WeightedEvaluation { + /** An instance. */ + private static final WeightedMean INSTANCE = new WeightedMean(); + + /** Create an instance. */ + private WeightedMean() { + // Do nothing + } + + /** + * Gets an instance. + * + * @return an instance + */ + public static WeightedMean getInstance() { + return INSTANCE; + } + + /** + * Returns the weighted arithmetic mean of the entries in the specified portion of + * the input array, or Double.NaN if the designated subarray + * is empty. + *

+ * Throws IllegalArgumentException if either array is null.

+ *

+ * See {@link WeightedMean} for details on the computing algorithm. The two-pass algorithm + * described above is used here, with weights applied in computing both the original + * estimate and the correction factor.

+ *

+ * Throws IllegalArgumentException if any of the following are true: + *

+ * + * @param values the input array + * @param weights the weights array + * @param begin index of the first array element to include + * @param length the number of elements to include + * @return the mean of the values or Double.NaN if length = 0 + * @throws MathIllegalArgumentException if the parameters are not valid + * @since 2.1 + */ + @Override + public double evaluate(final double[] values, final double[] weights, + final int begin, final int length) throws MathIllegalArgumentException { + if (MathArrays.verifyValues(values, weights, begin, length)) { + + // Compute initial estimate using definitional formula + final int end = begin + length; + double sumw = sum(weights, begin, end); + double xbarw = sum(values, weights, begin, end) / sumw; + + // Compute correction factor in second pass + double correction = 0; + for (int i = begin; i < end; i++) { + correction += weights[i] * (values[i] - xbarw); + } + return xbarw + (correction / sumw); + } + return Double.NaN; + } + + /** + * Returns the weighted arithmetic mean of the entries in the input array. + *

+ * Throws MathIllegalArgumentException if either array is null.

+ *

+ * See {@link WeightedMean} for details on the computing algorithm. The two-pass algorithm + * described above is used here, with weights applied in computing both the original + * estimate and the correction factor.

+ *

+ * Throws MathIllegalArgumentException if any of the following are true: + *

+ * + * @param values the input array + * @param weights the weights array + * @return the mean of the values or Double.NaN if length = 0 + * @throws MathIllegalArgumentException if the parameters are not valid + * @since 2.1 + */ + @Override + public double evaluate(final double[] values, final double[] weights) + throws MathIllegalArgumentException { + return evaluate(values, weights, 0, values.length); + } + + + /** + * Compute the sum of the values. + * + * @param values the values + * @param begin inclusive start index + * @param end exclusive end index + * @return the sum + */ + private static double sum(double[] values, int begin, int end) { + double sum = 0; + for (int i = begin; i < end; i++) { + sum += values[i]; + } + return sum; + } + + /** + * Compute the weighted sum of the values. + * + * @param values the values + * @param weights the weights + * @param begin inclusive start index + * @param end exclusive end index + * @return the sum + */ + private static double sum(double[] values, double[] weights, int begin, int end) { + double sum = 0; + for (int i = begin; i < end; i++) { + sum += values[i] * weights[i]; + } + return sum; + } +} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Variance.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedVariance.java similarity index 50% rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Variance.java rename to commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedVariance.java index 750f41c472..4ee155ce6c 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/Variance.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedVariance.java @@ -16,252 +16,48 @@ */ package org.apache.commons.math4.legacy.stat.descriptive.moment; +import org.apache.commons.math4.legacy.core.MathArrays; import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation; -import org.apache.commons.math4.legacy.core.MathArrays; /** - * Computes the variance of the available values. By default, the unbiased + * Computes the weighted variance of the available values. By default, the unbiased * "sample variance" definitional formula is used: *

- * variance = sum((x_i - mean)^2) / (n - 1)

- *

- * where mean is the {@link Mean} and n is the number - * of sample observations.

+ * variance = sum(w_i * (x_i - mean)^2) / (sum(w_i) - 1)

*

- * The definitional formula does not have good numerical properties, so - * this implementation does not compute the statistic using the definitional - * formula.

- * Note that adding values using increment or - * incrementAll and then executing getResult will - * sometimes give a different, less accurate, result than executing - * evaluate with the full array of values. The former approach - * should only be used when the full array of values is not available. + * where mean is the {@link WeightedMean} and w_i is the weight for + * observation x_i.

*

- * The "population variance" ( sum((x_i - mean)^2) / n ) can also + * The "population variance" using the denominator as sum(w_i) can also * be computed using this statistic. The isBiasCorrected * property determines whether the "population" or "sample" value is - * returned by the evaluate and getResult methods. + * returned by the evaluate methods. * To compute population variances, set this property to false. *

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

*/ -public class Variance extends AbstractStorelessUnivariateStatistic implements WeightedEvaluation { - /** SecondMoment is used in incremental calculation of Variance. */ - protected SecondMoment moment; - - /** - * Whether or not {@link #increment(double)} should increment - * the internal second moment. When a Variance is constructed with an - * external SecondMoment as a constructor parameter, this property is - * set to false and increments must be applied to the second moment - * directly. - */ - protected boolean incMoment = true; - +public final class WeightedVariance implements WeightedEvaluation { /** * Whether or not bias correction is applied when computing the * value of the statistic. True means that bias is corrected. See - * {@link Variance} for details on the formula. + * {@link WeightedVariance} for details on the formula. */ private boolean isBiasCorrected = true; /** - * Constructs a Variance with default (true) isBiasCorrected - * property. - */ - public Variance() { - moment = new SecondMoment(); - } - - /** - * Constructs a Variance based on an external second moment. - *

- * When this constructor is used, the statistic may only be - * incremented via the moment, i.e., {@link #increment(double)} - * does nothing; whereas {@code m2.increment(value)} increments - * both {@code m2} and the Variance instance constructed from it. - * - * @param m2 the SecondMoment (Third or Fourth moments work here as well.) - */ - public Variance(final SecondMoment m2) { - incMoment = false; - this.moment = m2; - } - - /** - * Constructs a Variance with the specified isBiasCorrected - * property. - * - * @param isBiasCorrected setting for bias correction - true means - * bias will be corrected and is equivalent to using the "no arg" - * constructor - */ - public Variance(boolean isBiasCorrected) { - moment = new SecondMoment(); - this.isBiasCorrected = isBiasCorrected; - } - - /** - * Constructs a Variance with the specified isBiasCorrected - * property and the supplied external second moment. - * - * @param isBiasCorrected setting for bias correction - true means - * bias will be corrected - * @param m2 the SecondMoment (Third or Fourth moments work - * here as well.) - */ - public Variance(boolean isBiasCorrected, SecondMoment m2) { - incMoment = false; - this.moment = m2; - this.isBiasCorrected = isBiasCorrected; - } - - /** - * Copy constructor, creates a new {@code Variance} identical - * to the {@code original}. - * - * @param original the {@code Variance} instance to copy - * @throws NullArgumentException if original is null - */ - public Variance(Variance original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - *

If all values are available, it is more accurate to use - * {@link #evaluate(double[])} rather than adding values one at a time - * using this method and then executing {@link #getResult}, since - * evaluate leverages the fact that is has the full - * list of values together to execute a two-pass algorithm. - * See {@link Variance}.

- * - *

Note also that when {@link #Variance(SecondMoment)} is used to - * create a Variance, this method does nothing. In that case, the - * SecondMoment should be incremented directly.

- */ - @Override - public void increment(final double d) { - if (incMoment) { - moment.increment(d); - } - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - if (moment.n == 0) { - return Double.NaN; - } else if (moment.n == 1) { - return 0d; - } else { - if (isBiasCorrected) { - return moment.m2 / (moment.n - 1d); - } else { - return moment.m2 / (moment.n); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return moment.getN(); - } - - /** - * {@inheritDoc} + * Constructs a Variance. */ - @Override - public void clear() { - if (incMoment) { - moment.clear(); - } + private WeightedVariance() { + // Do nothing } /** - * Returns the variance of the entries in the input array, or - * Double.NaN if the array is empty. - *

- * See {@link Variance} for details on the computing algorithm.

- *

- * Returns 0 for a single-value (i.e. length = 1) sample.

- *

- * Throws MathIllegalArgumentException if the array is null.

- *

- * Does not change the internal state of the statistic.

+ * Gets a new instance. * - * @param values the input array - * @return the variance of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null + * @return an instance */ - @Override - public double evaluate(final double[] values) throws MathIllegalArgumentException { - if (values == null) { - throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); - } - return evaluate(values, 0, values.length); - } - - /** - * Returns the variance of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. Note that Double.NaN may also be returned if the input - * includes NaN and / or infinite values. - *

- * See {@link Variance} for details on the computing algorithm.

- *

- * Returns 0 for a single-value (i.e. length = 1) sample.

- *

- * Does not change the internal state of the statistic.

- *

- * Throws MathIllegalArgumentException if the array is null.

- * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the variance of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - - double var = Double.NaN; - - if (MathArrays.verifyValues(values, begin, length)) { - if (length == 1) { - var = 0.0; - } else if (length > 1) { - Mean mean = new Mean(); - double m = mean.evaluate(values, begin, length); - var = evaluate(values, m, begin, length); - } - } - return var; + public static WeightedVariance getInstance() { + return new WeightedVariance(); } /** @@ -317,7 +113,7 @@ public double evaluate(final double[] values, final double[] weights, if (length == 1) { var = 0.0; } else if (length > 1) { - Mean mean = new Mean(); + WeightedMean mean = WeightedMean.getInstance(); double m = mean.evaluate(values, weights, begin, length); var = evaluate(values, weights, m, begin, length); } @@ -370,89 +166,6 @@ public double evaluate(final double[] values, final double[] weights) return evaluate(values, weights, 0, values.length); } - /** - * Returns the variance of the entries in the specified portion of - * the input array, using the precomputed mean value. Returns - * Double.NaN if the designated subarray is empty. - *

- * See {@link Variance} for details on the computing algorithm.

- *

- * The formula used assumes that the supplied mean value is the arithmetic - * mean of the sample data, not a known population parameter. This method - * is supplied only to save computation when the mean has already been - * computed.

- *

- * Returns 0 for a single-value (i.e. length = 1) sample.

- *

- * Throws MathIllegalArgumentException if the array is null.

- *

- * Does not change the internal state of the statistic.

- * - * @param values the input array - * @param mean the precomputed mean value - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the variance of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - public double evaluate(final double[] values, final double mean, - final int begin, final int length) throws MathIllegalArgumentException { - - double var = Double.NaN; - - if (MathArrays.verifyValues(values, begin, length)) { - if (length == 1) { - var = 0.0; - } else if (length > 1) { - double accum = 0.0; - double dev = 0.0; - double accum2 = 0.0; - for (int i = begin; i < begin + length; i++) { - dev = values[i] - mean; - accum += dev * dev; - accum2 += dev; - } - double len = length; - if (isBiasCorrected) { - var = (accum - (accum2 * accum2 / len)) / (len - 1.0); - } else { - var = (accum - (accum2 * accum2 / len)) / len; - } - } - } - return var; - } - - /** - * Returns the variance of the entries in the input array, using the - * precomputed mean value. Returns Double.NaN if the array - * is empty. - *

- * See {@link Variance} for details on the computing algorithm.

- *

- * If isBiasCorrected is true the formula used - * assumes that the supplied mean value is the arithmetic mean of the - * sample data, not a known population parameter. If the mean is a known - * population parameter, or if the "population" version of the variance is - * desired, set isBiasCorrected to false before - * invoking this method.

- *

- * Returns 0 for a single-value (i.e. length = 1) sample.

- *

- * Throws MathIllegalArgumentException if the array is null.

- *

- * Does not change the internal state of the statistic.

- * - * @param values the input array - * @param mean the precomputed mean value - * @return the variance of the values or Double.NaN if the array is empty - * @throws MathIllegalArgumentException if the array is null - */ - public double evaluate(final double[] values, final double mean) throws MathIllegalArgumentException { - return evaluate(values, mean, 0, values.length); - } - /** * Returns the weighted variance of the entries in the specified portion of * the input array, using the precomputed weighted mean value. Returns @@ -512,14 +225,12 @@ public double evaluate(final double[] values, final double[] weights, double accum = 0.0; double dev = 0.0; double accum2 = 0.0; - for (int i = begin; i < begin + length; i++) { + double sumWts = 0; + int end = begin + length; + for (int i = begin; i < end; i++) { dev = values[i] - mean; accum += weights[i] * (dev * dev); accum2 += weights[i] * dev; - } - - double sumWts = 0; - for (int i = begin; i < begin + length; i++) { sumWts += weights[i]; } @@ -597,32 +308,4 @@ public boolean isBiasCorrected() { public void setBiasCorrected(boolean biasCorrected) { this.isBiasCorrected = biasCorrected; } - - /** - * {@inheritDoc} - */ - @Override - public Variance copy() { - Variance result = new Variance(); - // No try-catch or advertised exception because parameters are guaranteed non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source Variance to copy - * @param dest Variance to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(Variance source, Variance dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.moment = source.moment.copy(); - dest.isBiasCorrected = source.isBiasCorrected; - dest.incMoment = source.incMoment; - } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/CentralPivotingStrategy.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/CentralPivotingStrategy.java deleted file mode 100644 index 833d1594f9..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/CentralPivotingStrategy.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import org.apache.commons.math4.legacy.core.MathArrays; - -/** - * A mid point strategy based on the average of begin and end indices. - * @since 3.4 - */ -public class CentralPivotingStrategy implements PivotingStrategy { - /** - * {@inheritDoc} - * This in particular picks a average of begin and end indices - * @return The index corresponding to a simple average of - * the first and the last element indices of the array slice - * @throws org.apache.commons.math4.legacy.exception.MathIllegalArgumentException MathIllegalArgumentException when indices exceeds range - */ - @Override - public int pivotIndex(final double[] work, final int begin, final int end) { - MathArrays.verifyValues(work, begin, end - begin); - return begin + (end - begin)/2; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/KthSelector.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/KthSelector.java deleted file mode 100644 index cad4a4940d..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/KthSelector.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import java.util.Arrays; - -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.core.jdkmath.JdkMath; - -/** - * A Simple Kth selector implementation to pick up the - * Kth ordered element from a work array containing the input - * numbers. - * @since 3.4 - */ -public class KthSelector { - /** Minimum selection size for insertion sort rather than selection. */ - private static final int MIN_SELECT_SIZE = 15; - - /** A {@link PivotingStrategy} used for pivoting. */ - private final PivotingStrategy pivotingStrategy; - - /** - * Constructor with default {@link MedianOf3PivotingStrategy median of 3} pivoting strategy. - */ - public KthSelector() { - this.pivotingStrategy = new MedianOf3PivotingStrategy(); - } - - /** - * Constructor with specified pivoting strategy. - * - * @param pivotingStrategy pivoting strategy to use - * @throws NullArgumentException when pivotingStrategy is null - * @see MedianOf3PivotingStrategy - * @see RandomPivotingStrategy - * @see CentralPivotingStrategy - */ - public KthSelector(final PivotingStrategy pivotingStrategy) { - NullArgumentException.check(pivotingStrategy); - this.pivotingStrategy = pivotingStrategy; - } - - /** Get the pivoting strategy. - * @return pivoting strategy - */ - public PivotingStrategy getPivotingStrategy() { - return pivotingStrategy; - } - - /** - * Select Kth value in the array. - * - * @param work work array to use to find out the Kth value - * @param pivotsHeap cached pivots heap that can be used for efficient estimation - * @param k the index whose value in the array is of interest - * @return Kth value - */ - public double select(final double[] work, final int[] pivotsHeap, final int k) { - int begin = 0; - int end = work.length; - int node = 0; - final boolean usePivotsHeap = pivotsHeap != null; - while (end - begin > MIN_SELECT_SIZE) { - final int pivot; - - if (usePivotsHeap && node < pivotsHeap.length && - pivotsHeap[node] >= 0) { - // the pivot has already been found in a previous call - // and the array has already been partitioned around it - pivot = pivotsHeap[node]; - } else { - // select a pivot and partition work array around it - pivot = partition(work, begin, end, pivotingStrategy.pivotIndex(work, begin, end)); - if (usePivotsHeap && node < pivotsHeap.length) { - pivotsHeap[node] = pivot; - } - } - - if (k == pivot) { - // the pivot was exactly the element we wanted - return work[k]; - } else if (k < pivot) { - // the element is in the left partition - end = pivot; - node = JdkMath.min(2 * node + 1, usePivotsHeap ? pivotsHeap.length : end); - } else { - // the element is in the right partition - begin = pivot + 1; - node = JdkMath.min(2 * node + 2, usePivotsHeap ? pivotsHeap.length : end); - } - } - Arrays.sort(work, begin, end); - return work[k]; - } - - /** - * Partition an array slice around a pivot.Partitioning exchanges array - * elements such that all elements smaller than pivot are before it and - * all elements larger than pivot are after it. - * - * @param work work array - * @param begin index of the first element of the slice of work array - * @param end index after the last element of the slice of work array - * @param pivot initial index of the pivot - * @return index of the pivot after partition - */ - private int partition(final double[] work, final int begin, final int end, final int pivot) { - - final double value = work[pivot]; - work[pivot] = work[begin]; - - int i = begin + 1; - int j = end - 1; - while (i < j) { - while (i < j && Double.compare(work[j], value) > 0) { - --j; - } - while (i < j && Double.compare(work[i], value) < 0) { - ++i; - } - - if (i < j) { - final double tmp = work[i]; - work[i++] = work[j]; - work[j--] = tmp; - } - } - - if (i >= end || Double.compare(work[i], value) > 0) { - --i; - } - work[begin] = work[i]; - work[i] = value; - return i; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Max.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Max.java deleted file mode 100644 index 038ab5d9a9..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Max.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.legacy.core.MathArrays; - -/** - * Returns the maximum of the available values. - * -*

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class Max extends AbstractStorelessUnivariateStatistic { - /** Number of values that have been added. */ - private long n; - - /** Current value of the statistic. */ - private double value; - - /** - * Create a Max instance. - */ - public Max() { - n = 0; - value = Double.NaN; - } - - /** - * Copy constructor, creates a new {@code Max} identical - * to the {@code original}. - * - * @param original the {@code Max} instance to copy - * @throws NullArgumentException if original is null - */ - public Max(Max original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - if (d > value || Double.isNaN(value)) { - value = d; - } - n++; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - value = Double.NaN; - n = 0; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return value; - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return n; - } - - /** - * Returns the maximum of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. - *

- * Throws MathIllegalArgumentException if the array is null or - * the array index parameters are not valid.

- * - * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the maximum of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - - double max = Double.NaN; - if (MathArrays.verifyValues(values, begin, length)) { - max = values[begin]; - for (int i = begin; i < begin + length; i++) { - if (!Double.isNaN(values[i])) { - max = (max > values[i]) ? max : values[i]; - } - } - } - return max; - } - - /** - * {@inheritDoc} - */ - @Override - public Max copy() { - Max result = new Max(); - // No try-catch or advertised exception because args are non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source Max to copy - * @param dest Max to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(Max source, Max dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.n = source.n; - dest.value = source.value; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Median.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Median.java deleted file mode 100644 index dc772698b4..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Median.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.statistics.ranking.NaNStrategy; - - -/** - * Returns the median of the available values. This is the same as the 50th percentile. - * See {@link Percentile} for a description of the algorithm used. - *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class Median extends Percentile { - /** Fixed quantile. */ - private static final double FIXED_QUANTILE_50 = 50.0; - - /** - * Default constructor. - */ - public Median() { - // No try-catch or advertised exception - arg is valid - super(FIXED_QUANTILE_50); - } - - /** - * Copy constructor, creates a new {@code Median} identical. - * to the {@code original} - * - * @param original the {@code Median} instance to copy - * @throws NullArgumentException if original is null - */ - public Median(Median original) throws NullArgumentException { - super(original); - } - - /** - * Constructs a Median with the specific {@link EstimationType}, {@link NaNStrategy} and {@link KthSelector}. - * - * @param estimationType one of the percentile {@link EstimationType estimation types} - * @param nanStrategy one of {@link NaNStrategy} to handle with NaNs - * @param kthSelector {@link KthSelector} to use for pivoting during search - * @throws MathIllegalArgumentException if p is not within (0,100] - * @throws NullArgumentException if type or NaNStrategy passed is null - */ - private Median(final EstimationType estimationType, final NaNStrategy nanStrategy, - final KthSelector kthSelector) - throws MathIllegalArgumentException { - super(FIXED_QUANTILE_50, estimationType, nanStrategy, kthSelector); - } - - /** {@inheritDoc} */ - @Override - public Median withEstimationType(final EstimationType newEstimationType) { - return new Median(newEstimationType, getNaNStrategy(), getKthSelector()); - } - - /** {@inheritDoc} */ - @Override - public Median withNaNStrategy(final NaNStrategy newNaNStrategy) { - return new Median(getEstimationType(), newNaNStrategy, getKthSelector()); - } - - /** {@inheritDoc} */ - @Override - public Median withKthSelector(final KthSelector newKthSelector) { - return new Median(getEstimationType(), getNaNStrategy(), newKthSelector); - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MedianOf3PivotingStrategy.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MedianOf3PivotingStrategy.java deleted file mode 100644 index eb89337e83..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MedianOf3PivotingStrategy.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import org.apache.commons.math4.legacy.core.MathArrays; - -/** - * Classic median of 3 strategy given begin and end indices. - * @since 3.4 - */ -public class MedianOf3PivotingStrategy implements PivotingStrategy { - /**{@inheritDoc} - * This in specific makes use of median of 3 pivoting. - * @return The index corresponding to a pivot chosen between the - * first, middle and the last indices of the array slice - * @throws org.apache.commons.math4.legacy.exception.MathIllegalArgumentException MathIllegalArgumentException when indices exceeds range - */ - @Override - public int pivotIndex(final double[] work, final int begin, final int end) { - MathArrays.verifyValues(work, begin, end - begin); - final int inclusiveEnd = end - 1; - final int middle = begin + (inclusiveEnd - begin) / 2; - final double wBegin = work[begin]; - final double wMiddle = work[middle]; - final double wEnd = work[inclusiveEnd]; - - if (wBegin < wMiddle) { - if (wMiddle < wEnd) { - return middle; - } else { - return wBegin < wEnd ? inclusiveEnd : begin; - } - } else { - if (wBegin < wEnd) { - return begin; - } else { - return wMiddle < wEnd ? inclusiveEnd : middle; - } - } - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Min.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Min.java deleted file mode 100644 index 8a185c5b29..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Min.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.legacy.core.MathArrays; - -/** - * Returns the minimum of the available values. - * - *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class Min extends AbstractStorelessUnivariateStatistic { - /**Number of values that have been added. */ - private long n; - - /**Current value of the statistic. */ - private double value; - - /** - * Create a Min instance. - */ - public Min() { - n = 0; - value = Double.NaN; - } - - /** - * Copy constructor, creates a new {@code Min} identical - * to the {@code original}. - * - * @param original the {@code Min} instance to copy - * @throws NullArgumentException if original is null - */ - public Min(Min original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - if (d < value || Double.isNaN(value)) { - value = d; - } - n++; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - value = Double.NaN; - n = 0; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return value; - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return n; - } - - /** - * Returns the minimum of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. - *

- * Throws MathIllegalArgumentException if the array is null or - * the array index parameters are not valid.

- * - * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the minimum of the values or Double.NaN if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - @Override - public double evaluate(final double[] values,final int begin, final int length) - throws MathIllegalArgumentException { - - double min = Double.NaN; - if (MathArrays.verifyValues(values, begin, length)) { - min = values[begin]; - for (int i = begin; i < begin + length; i++) { - if (!Double.isNaN(values[i])) { - min = (min < values[i]) ? min : values[i]; - } - } - } - return min; - } - - /** - * {@inheritDoc} - */ - @Override - public Min copy() { - Min result = new Min(); - // No try-catch or advertised exception - args are non-null - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source Min to copy - * @param dest Min to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(Min source, Min dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.n = source.n; - dest.value = source.value; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PSquarePercentile.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PSquarePercentile.java index 8184fb71d3..dd234aa07c 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PSquarePercentile.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PSquarePercentile.java @@ -18,7 +18,6 @@ import java.text.DecimalFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -47,7 +46,8 @@ *

* Note: This implementation is not synchronized and produces an approximate * result. For small samples, where data can be stored and processed in memory, - * {@link Percentile} should be used.

+ * {@link org.apache.commons.math4.legacy.stat.StatUtils#percentile(double[], double) StatUtils.percentile} + * should be used.

*/ public class PSquarePercentile extends AbstractStorelessUnivariateStatistic implements StorelessUnivariateStatistic { @@ -124,44 +124,6 @@ public PSquarePercentile(final double p) { this(DEFAULT_QUANTILE_DESIRED); } - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - double result = getResult(); - result = Double.isNaN(result) ? 37 : result; - final double markersHash = markers == null ? 0 : markers.hashCode(); - final double[] toHash = {result, quantile, markersHash, countOfObservations}; - return Arrays.hashCode(toHash); - } - - /** - * Returns true iff {@code o} is a {@code PSquarePercentile} returning the. - * same values as this for {@code getResult()} and {@code getN()} and also - * having equal markers - * - * @param o object to compare - * @return true if {@code o} is a {@code PSquarePercentile} with - * equivalent internal state - */ - @Override - public boolean equals(Object o) { - boolean result = false; - if (this == o) { - result = true; - } else if (o instanceof PSquarePercentile) { - PSquarePercentile that = (PSquarePercentile) o; - boolean isNotNull = markers != null && that.markers != null; - boolean isNull = markers == null && that.markers == null; - result = isNotNull ? markers.equals(that.markers) : isNull; - // markers as in the case of first - // five observations - result = result && getN() == that.getN(); - } - return result; - } - /** * {@inheritDoc}The internal state updated due to the new value in this * context is basically of the marker positions and computation of the @@ -377,33 +339,6 @@ private static Marker[] createMarkerArray( new Marker(initialFive.get(4), 5, 1, 5) }; } - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return Arrays.deepHashCode(markerArray); - } - - /** - * {@inheritDoc}.This equals method basically checks for marker array to - * be deep equals. - * - * @param o is the other object - * @return true if the object compares with this object are equivalent - */ - @Override - public boolean equals(Object o) { - boolean result = false; - if (this == o) { - result = true; - } else if (o instanceof Markers) { - Markers that = (Markers) o; - result = Arrays.deepEquals(markerArray, that.markerArray); - } - return result; - } - /** * Process a data point. * @@ -750,49 +685,6 @@ private boolean isEstimateBad(final double[] y, final double yD) { return yD <= y[0] || yD >= y[2]; } - /** - * {@inheritDoc}This equals method checks for marker attributes and - * as well checks if navigation pointers (next and previous) are the same - * between this and passed in object - * - * @param o Other object - * @return true if this equals passed in other object o - */ - @Override - public boolean equals(Object o) { - boolean result = false; - if (this == o) { - result = true; - } else if (o instanceof Marker) { - Marker that = (Marker) o; - - result = Double.compare(markerHeight, that.markerHeight) == 0; - result = - result && - Double.compare(intMarkerPosition, - that.intMarkerPosition) == 0; - result = - result && - Double.compare(desiredMarkerPosition, - that.desiredMarkerPosition) == 0; - result = - result && - Double.compare(desiredMarkerIncrement, - that.desiredMarkerIncrement) == 0; - - result = result && next.index == that.next.index; - result = result && previous.index == that.previous.index; - } - return result; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return Arrays.hashCode(new double[] {markerHeight, intMarkerPosition, - desiredMarkerIncrement, desiredMarkerPosition, previous.index, next.index}); - } - /** * Copy this instance. * @@ -877,7 +769,7 @@ public boolean addAll(Collection collection) { * @param p the quantile desired * @return an instance of PSquareMarkers */ - public static PSquareMarkers newMarkers(final List initialFive, final double p) { + static PSquareMarkers newMarkers(final List initialFive, final double p) { return new Markers(initialFive, p); } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Percentile.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Percentile.java deleted file mode 100644 index b5843b5e4c..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/Percentile.java +++ /dev/null @@ -1,1375 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import java.util.Arrays; -import java.util.BitSet; - -import org.apache.commons.numbers.core.Precision; -import org.apache.commons.numbers.arrays.SortInPlace; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NotPositiveException; -import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException; -import org.apache.commons.math4.legacy.exception.OutOfRangeException; -import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractUnivariateStatistic; -import org.apache.commons.math4.core.jdkmath.JdkMath; -import org.apache.commons.math4.legacy.core.MathArrays; -import org.apache.commons.statistics.ranking.NaNStrategy; - -/** - * Provides percentile computation. - *

- * There are several commonly used methods for estimating percentiles (a.k.a. - * quantiles) based on sample data. For large samples, the different methods - * agree closely, but when sample sizes are small, different methods will give - * significantly different results. The algorithm implemented here works as follows: - *

    - *
  1. Let n be the length of the (sorted) array and - * 0 < p <= 100 be the desired percentile.
  2. - *
  3. If n = 1 return the unique array element (regardless of - * the value of p); otherwise
  4. - *
  5. Compute the estimated percentile position - * pos = p * (n + 1) / 100 and the difference, d - * between pos and floor(pos) (i.e. the fractional - * part of pos).
  6. - *
  7. If pos < 1 return the smallest element in the array.
  8. - *
  9. Else if pos >= n return the largest element in the array.
  10. - *
  11. Else let lower be the element in position - * floor(pos) in the array and let upper be the - * next element in the array. Return lower + d * (upper - lower) - *
  12. - *
- *

- * To compute percentiles, the data must be at least partially ordered. Input - * arrays are copied and recursively partitioned using an ordering definition. - * The ordering used by Arrays.sort(double[]) is the one determined - * by {@link java.lang.Double#compareTo(Double)}. This ordering makes - * Double.NaN larger than any other value (including - * Double.POSITIVE_INFINITY). Therefore, for example, the median - * (50th percentile) of - * {0, 1, 2, 3, 4, Double.NaN} evaluates to 2.5.

- *

- * Since percentile estimation usually involves interpolation between array - * elements, arrays containing NaN or infinite values will often - * result in NaN or infinite values returned.

- *

- * Further, to include different estimation types such as R1, R2 as mentioned in - * Quantile page(wikipedia), - * a type specific NaN handling strategy is used to closely match with the - * typically observed results from popular tools like R(R1-R9), Excel(R7).

- *

- * Since 2.2, Percentile uses only selection instead of complete sorting - * and caches selection algorithm state between calls to the various - * {@code evaluate} methods. This greatly improves efficiency, both for a single - * percentile and multiple percentile computations. To maximize performance when - * multiple percentiles are computed based on the same data, users should set the - * data array once using either one of the {@link #evaluate(double[], double)} or - * {@link #setData(double[])} methods and thereafter {@link #evaluate(double)} - * with just the percentile provided. - *

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class Percentile extends AbstractUnivariateStatistic { - /** Maximum number of partitioning pivots cached (each level double the number of pivots). */ - private static final int MAX_CACHED_LEVELS = 10; - - /** Maximum number of cached pivots in the pivots cached array. */ - private static final int PIVOTS_HEAP_LENGTH = 0x1 << MAX_CACHED_LEVELS - 1; - - /** Default KthSelector used with default pivoting strategy. */ - private final KthSelector kthSelector; - - /** Any of the {@link EstimationType}s such as {@link EstimationType#LEGACY CM} can be used. */ - private final EstimationType estimationType; - - /** NaN Handling of the input as defined by {@link NaNStrategy}. */ - private final NaNStrategy nanStrategy; - - /** - * Determines what percentile is computed when evaluate() is activated - * with no quantile argument. - */ - private double quantile; - - /** Cached pivots. */ - private int[] cachedPivots; - - /** Weight. */ - private double[] weights; - /** - * Constructs a Percentile with the following defaults. - *
    - *
  • default quantile: 50.0, can be reset with {@link #setQuantile(double)}
  • - *
  • default estimation type: {@link EstimationType#LEGACY}, - * can be reset with {@link #withEstimationType(EstimationType)}
  • - *
  • default NaN strategy: {@link NaNStrategy#REMOVED}, - * can be reset with {@link #withNaNStrategy(NaNStrategy)}
  • - *
  • a KthSelector that makes use of {@link MedianOf3PivotingStrategy}, - * can be reset with {@link #withKthSelector(KthSelector)}
  • - *
- */ - public Percentile() { - // No try-catch or advertised exception here - arg is valid - this(50.0); - } - - /** - * Constructs a Percentile with the specific quantile value and the following. - *
    - *
  • default method type: {@link EstimationType#LEGACY}
  • - *
  • default NaN strategy: {@link NaNStrategy#REMOVED}
  • - *
  • a Kth Selector : {@link KthSelector}
  • - *
- * @param quantile the quantile - * @throws MathIllegalArgumentException if p is not greater than 0 and less - * than or equal to 100 - */ - public Percentile(final double quantile) { - this(quantile, EstimationType.LEGACY, NaNStrategy.REMOVED, - new KthSelector(new MedianOf3PivotingStrategy())); - } - - /** - * Copy constructor, creates a new {@code Percentile} identical. - * to the {@code original} - * - * @param original the {@code Percentile} instance to copy. - * Cannot be {@code null}. - */ - public Percentile(final Percentile original) { - NullArgumentException.check(original); - estimationType = original.getEstimationType(); - nanStrategy = original.getNaNStrategy(); - kthSelector = original.getKthSelector(); - - setData(original.getDataRef()); - if (original.cachedPivots != null) { - System.arraycopy(original.cachedPivots, 0, cachedPivots, 0, original.cachedPivots.length); - } - setQuantile(original.quantile); - } - - /** - * Constructs a Percentile with the specific quantile value, - * {@link EstimationType}, {@link NaNStrategy} and {@link KthSelector}. - * - * @param quantile the quantile to be computed - * @param estimationType one of the percentile {@link EstimationType estimation types} - * @param nanStrategy one of {@link NaNStrategy} to handle with NaNs. - * Cannot be {@code null}. - * @param kthSelector a {@link KthSelector} to use for pivoting during search - * @throws MathIllegalArgumentException if p is not within (0,100] - */ - protected Percentile(final double quantile, - final EstimationType estimationType, - final NaNStrategy nanStrategy, - final KthSelector kthSelector) { - setQuantile(quantile); - cachedPivots = null; - NullArgumentException.check(estimationType); - NullArgumentException.check(nanStrategy); - NullArgumentException.check(kthSelector); - this.estimationType = estimationType; - this.nanStrategy = nanStrategy; - this.kthSelector = kthSelector; - } - - /** {@inheritDoc} */ - @Override - public void setData(final double[] values) { - if (values == null) { - cachedPivots = null; - } else { - cachedPivots = new int[PIVOTS_HEAP_LENGTH]; - Arrays.fill(cachedPivots, -1); - } - super.setData(values); - } - /** - * Set the data array. - * @param values Data array. - * Cannot be {@code null}. - * @param sampleWeights corresponding positive and non-NaN weights. - * Cannot be {@code null}. - * @throws MathIllegalArgumentException if lengths of values and weights are not equal. - * @throws org.apache.commons.math4.legacy.exception.NotANumberException if any weight is NaN - * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if any weight is not positive - */ - public void setData(final double[] values, - final double[] sampleWeights) { - setData(values, sampleWeights, 0, values.length); - } - - /** {@inheritDoc} */ - @Override - public void setData(final double[] values, final int begin, final int length) { - if (values == null) { - cachedPivots = null; - } else { - cachedPivots = new int[PIVOTS_HEAP_LENGTH]; - Arrays.fill(cachedPivots, -1); - } - super.setData(values, begin, length); - } - /** - * Set the data and weights arrays. The input array is copied, not referenced. - * @param values Data array. - * Cannot be {@code null}. - * @param sampleWeights corresponding positive and non-NaN weights. - * Cannot be {@code null}. - * @param begin the index of the first element to include - * @param length the number of elements to include - * @throws MathIllegalArgumentException if lengths of values and weights are not equal or values or weights is null - * @throws NotPositiveException if begin or length is not positive - * @throws NumberIsTooLargeException if begin + length is greater than values.length - * @throws org.apache.commons.math4.legacy.exception.NotANumberException if any weight is NaN - * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if any weight is not positive - */ - public void setData(final double[] values, - final double[] sampleWeights, - final int begin, - final int length) { - if (begin < 0) { - throw new NotPositiveException(LocalizedFormats.START_POSITION, begin); - } - - if (length < 0) { - throw new NotPositiveException(LocalizedFormats.LENGTH, length); - } - - if (begin + length > values.length) { - throw new NumberIsTooLargeException(LocalizedFormats.SUBARRAY_ENDS_AFTER_ARRAY_END, - begin + length, values.length, true); - } - - if (sampleWeights == null) { - throw new MathIllegalArgumentException(LocalizedFormats.NULL_NOT_ALLOWED); - } - cachedPivots = new int[PIVOTS_HEAP_LENGTH]; - Arrays.fill(cachedPivots, -1); - - // Check length - if (values.length != sampleWeights.length) { - throw new MathIllegalArgumentException(LocalizedFormats.LENGTH, - values, sampleWeights); - } - // Check weights > 0 - MathArrays.checkPositive(sampleWeights); - MathArrays.checkNotNaN(sampleWeights); - - super.setData(values, begin, length); - weights = new double[length]; - System.arraycopy(sampleWeights, begin, weights, 0, length); - } - /** - * Returns the result of evaluating the statistic over the stored data. - * If weights have been set, it will compute weighted percentile. - *

- * The stored array is the one which was set by previous calls to - * {@link #setData(double[])} or {@link #setData(double[], double[], int, int)} - *

- * @param p the percentile value to compute - * @return the value of the statistic applied to the stored data - * @throws MathIllegalArgumentException if lengths of values and weights are not equal or values or weights is null - * @throws NotPositiveException if begin, length is negative - * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if any weight is not positive - * @throws org.apache.commons.math4.legacy.exception.NotANumberException if any weight is NaN - * @throws OutOfRangeException if p is invalid - * @throws NumberIsTooLargeException if begin + length is greater than values.length - * (p must be greater than 0 and less than or equal to 100) - */ - public double evaluate(final double p) { - if (weights == null) { - return evaluate(getDataRef(), p); - } else { - return evaluate(getDataRef(), weights, p); - } - } - - /** - * Returns an estimate of the pth percentile of the values - * in the values array. - *

- * Calls to this method do not modify the internal quantile - * state of this statistic.

- *
    - *
  • Returns Double.NaN if values has length - * 0
  • - *
  • Returns (for any value of p) values[0] - * if values has length 1
  • - *
  • Throws MathIllegalArgumentException if values - * is null or p is not a valid quantile value (p must be greater than 0 - * and less than or equal to 100)
  • - *
- *

- * See {@link Percentile} for a description of the percentile estimation - * algorithm used.

- * - * @param values input array of values - * @param p the percentile value to compute - * @return the percentile value or Double.NaN if the array is empty - * @throws MathIllegalArgumentException if values is null or p is invalid - */ - public double evaluate(final double[] values, final double p) { - MathArrays.verifyValues(values, 0, 0); - return evaluate(values, 0, values.length, p); - } - /** - * Returns an estimate of the pth percentile of the values - * in the values array with their weights. - *

- * See {@link Percentile} for a description of the percentile estimation - * algorithm used.

- * @param values input array of values - * @param sampleWeights weights of values - * @param p the percentile value to compute - * @return the weighted percentile value or Double.NaN if the array is empty - * @throws MathIllegalArgumentException if lengths of values and weights are not equal or values or weights is null - * @throws NotPositiveException if begin, length is negative - * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if any weight is not positive - * @throws org.apache.commons.math4.legacy.exception.NotANumberException if any weight is NaN - * @throws OutOfRangeException if p is invalid - * @throws NumberIsTooLargeException if begin + length is greater than values.length - */ - public double evaluate(final double[] values, final double[] sampleWeights, final double p) { - MathArrays.verifyValues(values, 0, 0); - MathArrays.verifyValues(sampleWeights, 0, 0); - return evaluate(values, sampleWeights, 0, values.length, p); - } - - /** - * Returns an estimate of the quantileth percentile of the - * designated values in the values array. The quantile - * estimated is determined by the quantile property. - *
    - *
  • Returns Double.NaN if length = 0
  • - *
  • Returns (for any value of quantile) - * values[begin] if length = 1
  • - *
  • Throws MathIllegalArgumentException if values - * is null, or start or length is invalid
  • - *
- *

- * See {@link Percentile} for a description of the percentile estimation - * algorithm used.

- * - * @param values the input array - * @param start index of the first array element to include - * @param length the number of elements to include - * @return the percentile value - * @throws MathIllegalArgumentException if the parameters are not valid - * - */ - @Override - public double evaluate(final double[] values, final int start, final int length) { - return evaluate(values, start, length, quantile); - } - /** - * Returns an estimate of the weighted quantileth percentile of the - * designated values in the values array. The quantile - * estimated is determined by the quantile property. - *

- * See {@link Percentile} for a description of the percentile estimation - * algorithm used.

- * - * @param values the input array - * @param sampleWeights the weights of values - * @param start index of the first array element to include - * @param length the number of elements to include - * @return the percentile value - * @throws MathIllegalArgumentException if lengths of values and weights are not equal or values or weights is null - * @throws NotPositiveException if begin, length is negative - * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if any weight is not positive - * @throws org.apache.commons.math4.legacy.exception.NotANumberException if any weight is NaN - * @throws OutOfRangeException if p is invalid - * @throws NumberIsTooLargeException if begin + length is greater than values.length - */ - public double evaluate(final double[] values, final double[] sampleWeights, - final int start, final int length) { - return evaluate(values, sampleWeights, start, length, quantile); - } - - /** - * Returns an estimate of the pth percentile of the values - * in the values array, starting with the element in (0-based) - * position begin in the array and including length - * values. - *

- * Calls to this method do not modify the internal quantile - * state of this statistic.

- *
    - *
  • Returns Double.NaN if length = 0
  • - *
  • Returns (for any value of p) values[begin] - * if length = 1
  • - *
  • Throws MathIllegalArgumentException if values - * is null , begin or length is invalid, or - * p is not a valid quantile value (p must be greater than 0 - * and less than or equal to 100)
  • - *
- *

- * See {@link Percentile} for a description of the percentile estimation - * algorithm used.

- * - * @param values array of input values - * @param p the percentile to compute - * @param begin the first (0-based) element to include in the computation - * @param length the number of array elements to include - * @return the percentile value. - * @throws MathIllegalArgumentException if the parameters are not valid. - */ - public double evaluate(final double[] values, final int begin, - final int length, final double p) { - MathArrays.verifyValues(values, begin, length); - if (p > 100 || p <= 0) { - throw new OutOfRangeException(LocalizedFormats.OUT_OF_BOUNDS_QUANTILE_VALUE, - p, 0, 100); - } - if (length == 0) { - return Double.NaN; - } - if (length == 1) { - return values[begin]; // always return single value for n = 1 - } - - final double[] work = getWorkArray(values, begin, length); - final int[] pivotsHeap = getPivots(values); - return work.length == 0 ? - Double.NaN : - estimationType.evaluate(work, pivotsHeap, p, kthSelector); - } - /** - * Returns an estimate of the pth percentile of the values - * in the values array with sampleWeights, starting with the element in (0-based) - * position begin in the array and including length - * values. - *

- * See {@link Percentile} for a description of the percentile estimation - * algorithm used.

- * - * @param values array of input values - * @param sampleWeights positive and non-NaN weights of values - * @param begin the first (0-based) element to include in the computation - * @param length the number of array elements to include - * @param p percentile to compute - * @return the weighted percentile value - * @throws MathIllegalArgumentException if lengths of values and weights are not equal or values or weights is null - * @throws NotPositiveException if begin, length is negative - * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if any weight is not positive - * @throws org.apache.commons.math4.legacy.exception.NotANumberException if any weight is NaN - * @throws OutOfRangeException if p is invalid - * @throws NumberIsTooLargeException if begin + length is greater than values.length - */ - public double evaluate(final double[] values, final double[] sampleWeights, final int begin, - final int length, final double p) { - if (values == null || sampleWeights == null) { - throw new MathIllegalArgumentException(LocalizedFormats.NULL_NOT_ALLOWED); - } - // Check length - if (values.length != sampleWeights.length) { - throw new MathIllegalArgumentException(LocalizedFormats.LENGTH, - values, sampleWeights); - } - MathArrays.verifyValues(values, begin, length); - MathArrays.verifyValues(sampleWeights, begin, length); - MathArrays.checkPositive(sampleWeights); - MathArrays.checkNotNaN(sampleWeights); - - if (p > 100 || p <= 0) { - throw new OutOfRangeException(LocalizedFormats.OUT_OF_BOUNDS_QUANTILE_VALUE, - p, 0, 100); - } - if (length == 0) { - return Double.NaN; - } - if (length == 1) { - // Always return single value for n = 1 - return values[begin]; - } - - final double[] work = getWorkArray(values, begin, length); - final double[] workWeights = getWorkArray(values, sampleWeights, begin, length); - return work.length == 0 ? Double.NaN : - estimationType.evaluate(work, workWeights, p); - } - /** - * Returns the value of the quantile field (determines what percentile is - * computed when evaluate() is called with no quantile argument). - * - * @return quantile set while construction or {@link #setQuantile(double)} - */ - public double getQuantile() { - return quantile; - } - - /** - * Sets the value of the quantile field (determines what percentile is - * computed when evaluate() is called with no quantile argument). - * - * @param p a value between 0 < p <= 100 - * @throws MathIllegalArgumentException if p is not greater than 0 and less - * than or equal to 100 - */ - public void setQuantile(final double p) { - if (p <= 0 || p > 100) { - throw new OutOfRangeException(LocalizedFormats.OUT_OF_BOUNDS_QUANTILE_VALUE, - p, 0, 100); - } - quantile = p; - } - - /** - * {@inheritDoc} - */ - @Override - public Percentile copy() { - return new Percentile(this); - } - - /** - * Get the work array to operate. Makes use of prior {@code storedData} if - * it exists or else do a check on NaNs and copy a subset of the array - * defined by begin and length parameters. The set {@link #nanStrategy} will - * be used to either retain/remove/replace any NaNs present before returning - * the resultant array. - * - * @param values the array of numbers - * @param begin index to start reading the array - * @param length the length of array to be read from the begin index - * @return work array sliced from values in the range [begin,begin+length) - * @throws MathIllegalArgumentException if values or indices are invalid - */ - private double[] getWorkArray(final double[] values, final int begin, final int length) { - final double[] work; - if (values == getDataRef()) { - work = getDataRef(); - } else { - switch (nanStrategy) { - case MAXIMAL: // Replace NaNs with +INFs - work = replaceAndSlice(values, begin, length, Double.NaN, Double.POSITIVE_INFINITY); - break; - case MINIMAL: // Replace NaNs with -INFs - work = replaceAndSlice(values, begin, length, Double.NaN, Double.NEGATIVE_INFINITY); - break; - case REMOVED: // Drop NaNs from data - work = removeAndSlice(values, begin, length, Double.NaN); - break; - case FAILED: // NaN is not acceptable - work = copyOf(values, begin, length); - MathArrays.checkNotNaN(work); - break; - default: // FIXED - work = copyOf(values,begin,length); - break; - } - } - return work; - } - /** - * Get the work arrays of weights to operate. - * - * @param values the array of numbers - * @param sampleWeights the array of weights - * @param begin index to start reading the array - * @param length the length of array to be read from the begin index - * @return work array sliced from values in the range [begin,begin+length) - */ - protected double[] getWorkArray(final double[] values, final double[] sampleWeights, - final int begin, final int length) { - final double[] work; - if (values == getDataRef()) { - work = this.weights; - } else { - switch (nanStrategy) { - case REMOVED: // Drop weight if the data is NaN - work = removeAndSliceByRef(values, sampleWeights, begin, length, Double.NaN); - break; - default: // FIXED - work = copyOf(sampleWeights, begin, length); - break; - } - } - return work; - } - /** - * Make a copy of the array for the slice defined by array part from. - * [begin, begin+length) - * @param values the input array - * @param begin start index of the array to include - * @param length number of elements to include from begin - * @return copy of a slice of the original array - */ - private static double[] copyOf(final double[] values, final int begin, final int length) { - MathArrays.verifyValues(values, begin, length); - return Arrays.copyOfRange(values, begin, begin + length); - } - - /** - * Replace every occurrence of a given value with a replacement value in a - * copied slice of array defined by array part from [begin, begin+length). - * - * @param values the input array - * @param begin start index of the array to include - * @param length number of elements to include from begin - * @param original the value to be replaced with - * @param replacement the value to be used for replacement - * @return the copy of sliced array with replaced values - */ - private static double[] replaceAndSlice(final double[] values, - final int begin, final int length, - final double original, - final double replacement) { - final double[] temp = copyOf(values, begin, length); - for(int i = 0; i < length; i++) { - temp[i] = Precision.equalsIncludingNaN(original, temp[i]) ? - replacement : - temp[i]; - } - - return temp; - } - /** - * Remove the occurrence of a given value in a copied slice of array - * defined by the array part from [begin, begin+length). - * @param values the input array - * @param begin start index of the array to include - * @param length number of elements to include from begin - * @param removedValue the value to be removed from the sliced array - * @return the copy of the sliced array after removing the removedValue - */ - private static double[] removeAndSlice(final double[] values, - final int begin, final int length, - final double removedValue) { - MathArrays.verifyValues(values, begin, length); - final double[] temp; - // Indicates where the removedValue is located - final BitSet bits = new BitSet(length); - for (int i = begin; i < begin+length; i++) { - if (Precision.equalsIncludingNaN(removedValue, values[i])) { - bits.set(i - begin); - } - } - // Check if empty then create a new copy - if (bits.isEmpty()) { - // Nothing removed, just copy - temp = copyOf(values, begin, length); - } else if(bits.cardinality() == length) { - // All removed, just empty - temp = new double[0]; - } else { - // Some removable, so new - temp = new double[length - bits.cardinality()]; - // Index from source array (i.e values) - int start = begin; - // Index in destination array(i.e temp) - int dest = 0; - // Index of bit set of next one - int nextOne = -1; - // Start index pointer of bitset - int bitSetPtr = 0; - while ((nextOne = bits.nextSetBit(bitSetPtr)) != -1) { - final int lengthToCopy = nextOne - bitSetPtr; - System.arraycopy(values, start, temp, dest, lengthToCopy); - dest += lengthToCopy; - start = begin + (bitSetPtr = bits.nextClearBit(nextOne)); - } - // Copy any residue past start index till begin+length - if (start < begin + length) { - System.arraycopy(values,start,temp,dest,begin + length - start); - } - } - return temp; - } - /** - * Remove weights element if the corresponding data is equal to the given value. - * in [begin, begin+length) - * - * @param values the input array - * @param sampleWeights weights of the input array - * @param begin start index of the array to include - * @param length number of elements to include from begin - * @param removedValue the value to be removed from the sliced array - * @return the copy of the sliced array after removing weights - */ - private static double[] removeAndSliceByRef(final double[] values, - final double[] sampleWeights, - final int begin, final int length, - final double removedValue) { - MathArrays.verifyValues(values, begin, length); - final double[] temp; - //BitSet(length) to indicate where the removedValue is located - final BitSet bits = new BitSet(length); - for (int i = begin; i < begin+length; i++) { - if (Precision.equalsIncludingNaN(removedValue, values[i])) { - bits.set(i - begin); - } - } - //Check if empty then create a new copy - if (bits.isEmpty()) { - temp = copyOf(sampleWeights, begin, length); // Nothing removed, just copy - } else if(bits.cardinality() == length) { - temp = new double[0]; // All removed, just empty - }else { // Some removable, so new - temp = new double[length - bits.cardinality()]; - int start = begin; //start index from source array (i.e sampleWeights) - int dest = 0; //dest index in destination array(i.e temp) - int nextOne = -1; //nextOne is the index of bit set of next one - int bitSetPtr = 0; //bitSetPtr is start index pointer of bitset - while ((nextOne = bits.nextSetBit(bitSetPtr)) != -1) { - final int lengthToCopy = nextOne - bitSetPtr; - System.arraycopy(sampleWeights, start, temp, dest, lengthToCopy); - dest += lengthToCopy; - start = begin + (bitSetPtr = bits.nextClearBit(nextOne)); - } - //Copy any residue past start index till begin+length - if (start < begin + length) { - System.arraycopy(sampleWeights,start,temp,dest,begin + length - start); - } - } - return temp; - } - /** - * Get pivots which is either cached or a newly created one. - * - * @param values array containing the input numbers - * @return cached pivots or a newly created one - */ - private int[] getPivots(final double[] values) { - final int[] pivotsHeap; - if (values == getDataRef()) { - pivotsHeap = cachedPivots; - } else { - pivotsHeap = new int[PIVOTS_HEAP_LENGTH]; - Arrays.fill(pivotsHeap, -1); - } - return pivotsHeap; - } - - /** - * Get the estimation {@link EstimationType type} used for computation. - * - * @return the {@code estimationType} set - */ - public EstimationType getEstimationType() { - return estimationType; - } - - /** - * Build a new instance similar to the current one except for the - * {@link EstimationType estimation type}. - *

- * This method is intended to be used as part of a fluent-type builder - * pattern. Building finely tune instances should be done as follows: - *

- *
-     *   Percentile customized = new Percentile(quantile).
-     *                           withEstimationType(estimationType).
-     *                           withNaNStrategy(nanStrategy).
-     *                           withKthSelector(kthSelector);
-     * 
- *

- * If any of the {@code withXxx} method is omitted, the default value for - * the corresponding customization parameter will be used. - *

- * @param newEstimationType estimation type for the new instance. - * Cannot be {@code null}. - * @return a new instance, with changed estimation type - */ - public Percentile withEstimationType(final EstimationType newEstimationType) { - return new Percentile(quantile, newEstimationType, nanStrategy, kthSelector); - } - - /** - * Get the {@link NaNStrategy NaN Handling} strategy used for computation. - * @return {@code NaN Handling} strategy set during construction - */ - public NaNStrategy getNaNStrategy() { - return nanStrategy; - } - - /** - * Build a new instance similar to the current one except for the - * {@link NaNStrategy NaN handling} strategy. - *

- * This method is intended to be used as part of a fluent-type builder - * pattern. Building finely tune instances should be done as follows: - *

- *
-     *   Percentile customized = new Percentile(quantile).
-     *                           withEstimationType(estimationType).
-     *                           withNaNStrategy(nanStrategy).
-     *                           withKthSelector(kthSelector);
-     * 
- *

- * If any of the {@code withXxx} method is omitted, the default value for - * the corresponding customization parameter will be used. - *

- * @param newNaNStrategy NaN strategy for the new instance. - * Cannot be {@code null}. - * @return a new instance, with changed NaN handling strategy - */ - public Percentile withNaNStrategy(final NaNStrategy newNaNStrategy) { - return new Percentile(quantile, estimationType, newNaNStrategy, kthSelector); - } - - /** - * Get the {@link KthSelector kthSelector} used for computation. - * @return the {@code kthSelector} set - */ - public KthSelector getKthSelector() { - return kthSelector; - } - - /** - * Get the {@link PivotingStrategy} used in KthSelector for computation. - * @return the pivoting strategy set - */ - public PivotingStrategy getPivotingStrategy() { - return kthSelector.getPivotingStrategy(); - } - - /** - * Build a new instance similar to the current one except for the - * {@link KthSelector kthSelector} instance specifically set. - *

- * This method is intended to be used as part of a fluent-type builder - * pattern. Building finely tune instances should be done as follows: - *

- *
-     *   Percentile customized = new Percentile(quantile).
-     *                           withEstimationType(estimationType).
-     *                           withNaNStrategy(nanStrategy).
-     *                           withKthSelector(newKthSelector);
-     * 
- *

- * If any of the {@code withXxx} method is omitted, the default value for - * the corresponding customization parameter will be used. - *

- * @param newKthSelector KthSelector for the new instance. - * Cannot be {@code null}. - * @return a new instance, with changed KthSelector - */ - public Percentile withKthSelector(final KthSelector newKthSelector) { - return new Percentile(quantile, estimationType, nanStrategy, newKthSelector); - } - - /** - * An enum for various estimation strategies of a percentile referred in - * wikipedia on quantile - * with the names of enum matching those of types mentioned in - * wikipedia. - *

- * Each enum corresponding to the specific type of estimation in wikipedia - * implements the respective formulae that specializes in the below aspects - *

    - *
  • An index method to calculate approximate index of the - * estimate
  • - *
  • An estimate method to estimate a value found at the earlier - * computed index
  • - *
  • A minLimit on the quantile for which first element of sorted - * input is returned as an estimate
  • - *
  • A maxLimit on the quantile for which last element of sorted - * input is returned as an estimate
  • - *
- *

- * Users can now create {@link Percentile} by explicitly passing this enum; - * such as by invoking {@link Percentile#withEstimationType(EstimationType)} - *

- * References: - *

    - *
  1. - * Wikipedia on quantile - *
  2. - *
  3. - * - * Hyndman, R. J. and Fan, Y. (1996) Sample quantiles in statistical - * packages, American Statistician 50, 361–365
  4. - *
  5. - * - * R-Manual
  6. - *
- */ - public enum EstimationType { - /** - * This is the default type used in the {@link Percentile}.This method. - * has the following formulae for index and estimates
- * \( \begin{align} - * &index = (N+1)p\ \\ - * &estimate = x_{\lceil h\,-\,1/2 \rceil} \\ - * &minLimit = 0 \\ - * &maxLimit = 1 \\ - * \end{align}\) - */ - LEGACY("Legacy Apache Commons Math") { - /** - * {@inheritDoc}.This method in particular makes use of existing - * Apache Commons Math style of picking up the index. - */ - @Override - protected double index(final double p, final int length) { - final double minLimit = 0d; - final double maxLimit = 1d; - return Double.compare(p, minLimit) == 0 ? 0 : - Double.compare(p, maxLimit) == 0 ? - length : p * (length + 1); - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - /** - * The method R_1 has the following formulae for index and estimates.
- * \( \begin{align} - * &index= Np + 1/2\, \\ - * &estimate= x_{\lceil h\,-\,1/2 \rceil} \\ - * &minLimit = 0 \\ - * \end{align}\) - */ - R_1("R-1") { - - @Override - protected double index(final double p, final int length) { - final double minLimit = 0d; - return Double.compare(p, minLimit) == 0 ? 0 : length * p + 0.5; - } - - /** - * {@inheritDoc}This method in particular for R_1 uses ceil(pos-0.5) - */ - @Override - protected double estimate(final double[] values, - final int[] pivotsHeap, final double pos, - final int length, final KthSelector selector) { - return super.estimate(values, pivotsHeap, JdkMath.ceil(pos - 0.5), length, selector); - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - /** - * The method R_2 has the following formulae for index and estimates.
- * \( \begin{align} - * &index= Np + 1/2\, \\ - * &estimate=\frac{x_{\lceil h\,-\,1/2 \rceil} + - * x_{\lfloor h\,+\,1/2 \rfloor}}{2} \\ - * &minLimit = 0 \\ - * &maxLimit = 1 \\ - * \end{align}\) - */ - R_2("R-2") { - - @Override - protected double index(final double p, final int length) { - final double minLimit = 0d; - final double maxLimit = 1d; - return Double.compare(p, maxLimit) == 0 ? length : - Double.compare(p, minLimit) == 0 ? 0 : length * p + 0.5; - } - - /** - * {@inheritDoc}This method in particular for R_2 averages the - * values at ceil(p+0.5) and floor(p-0.5). - */ - @Override - protected double estimate(final double[] values, - final int[] pivotsHeap, final double pos, - final int length, final KthSelector selector) { - final double low = - super.estimate(values, pivotsHeap, JdkMath.ceil(pos - 0.5), length, selector); - final double high = - super.estimate(values, pivotsHeap,JdkMath.floor(pos + 0.5), length, selector); - return (low + high) / 2; - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - /** - * The method R_3 has the following formulae for index and estimates.
- * \( \begin{align} - * &index= Np \\ - * &estimate= x_{\lfloor h \rceil}\, \\ - * &minLimit = 0.5/N \\ - * \end{align}\) - */ - R_3("R-3") { - @Override - protected double index(final double p, final int length) { - final double minLimit = 1d/2 / length; - return Double.compare(p, minLimit) <= 0 ? - 0 : JdkMath.rint(length * p); - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - /** - * The method R_4 has the following formulae for index and estimates.
- * \( \begin{align} - * &index= Np\, \\ - * &estimate= x_{\lfloor h \rfloor} + (h - - * \lfloor h \rfloor) (x_{\lfloor h \rfloor + 1} - x_{\lfloor h - * \rfloor}) \\ - * &minLimit = 1/N \\ - * &maxLimit = 1 \\ - * \end{align}\) - */ - R_4("R-4") { - @Override - protected double index(final double p, final int length) { - final double minLimit = 1d / length; - final double maxLimit = 1d; - return Double.compare(p, minLimit) < 0 ? 0 : - Double.compare(p, maxLimit) == 0 ? length : length * p; - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - /** - * The method R_5 has the following formulae for index and estimates.
- * \( \begin{align} - * &index= Np + 1/2\\ - * &estimate= x_{\lfloor h \rfloor} + (h - - * \lfloor h \rfloor) (x_{\lfloor h \rfloor + 1} - x_{\lfloor h - * \rfloor}) \\ - * &minLimit = 0.5/N \\ - * &maxLimit = (N-0.5)/N - * \end{align}\) - */ - R_5("R-5") { - - @Override - protected double index(final double p, final int length) { - final double minLimit = 1d/2 / length; - final double maxLimit = (length - 0.5) / length; - return Double.compare(p, minLimit) < 0 ? 0 : - Double.compare(p, maxLimit) >= 0 ? - length : length * p + 0.5; - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - /** - * The method R_6 has the following formulae for index and estimates.
- * \( \begin{align} - * &index= (N + 1)p \\ - * &estimate= x_{\lfloor h \rfloor} + (h - - * \lfloor h \rfloor) (x_{\lfloor h \rfloor + 1} - x_{\lfloor h - * \rfloor}) \\ - * &minLimit = 1/(N+1) \\ - * &maxLimit = N/(N+1) \\ - * \end{align}\) - *

- * Note: This method computes the index in a manner very close to - * the default Commons Math Percentile existing implementation. However - * the difference to be noted is in picking up the limits with which - * first element (p<1(N+1)) and last elements (p>N/(N+1))are done. - * While in default case; these are done with p=0 and p=1 respectively. - */ - R_6("R-6") { - - @Override - protected double index(final double p, final int length) { - final double minLimit = 1d / (length + 1); - final double maxLimit = 1d * length / (length + 1); - return Double.compare(p, minLimit) < 0 ? 0 : - Double.compare(p, maxLimit) >= 0 ? - length : (length + 1) * p; - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - - /** - * The method R_7 implements Microsoft Excel style computation has the - * following formulae for index and estimates.
- * \( \begin{align} - * &index = (N-1)p + 1 \\ - * &estimate = x_{\lfloor h \rfloor} + (h - - * \lfloor h \rfloor) (x_{\lfloor h \rfloor + 1} - x_{\lfloor h - * \rfloor}) \\ - * &minLimit = 0 \\ - * &maxLimit = 1 \\ - * \end{align}\) - * The formula to evaluate weighted percentiles is as following.
- * \( \begin{align} - * &S_k = (k-1)w_k + (n-1)\sum_{i=1}^{k-1}w_i - * &Then find k s.t. \frac{S_k}{S_n}\leq p \leq \frac{S_{k+1}}{S_n} - * \end{align}\) - */ - R_7("R-7") { - @Override - protected double index(final double p, final int length) { - final double minLimit = 0d; - final double maxLimit = 1d; - return Double.compare(p, minLimit) == 0 ? 0 : - Double.compare(p, maxLimit) == 0 ? - length : 1 + (length - 1) * p; - } - - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - SortInPlace.ASCENDING.apply(work, sampleWeights); - double[] sk = new double[work.length]; - for(int k = 0; k < work.length; k++) { - sk[k] = 0; - for (int j = 0; j < k; j++) { - sk[k] += sampleWeights[j]; - } - sk[k] = k * sampleWeights[k] + (work.length - 1) * sk[k]; - } - - double qsn = (p / 100) * sk[sk.length-1]; - int k = searchSk(qsn, sk, 0, work.length - 1); - - double ret; - if (qsn == sk[k] && k == work.length - 1) { - ret = work[k] - (work[k] - work[k-1]) * (1 - (qsn - sk[k]) / (sk[k] - sk[k-1])); - } else { - ret = work[k] + (work[k+1] - work[k]) * (qsn - sk[k]) / (sk[k+1] - sk[k]); - } - return ret; - } - }, - - /** - * The method R_8 has the following formulae for index and estimates.
- * \( \begin{align} - * &index = (N + 1/3)p + 1/3 \\ - * &estimate = x_{\lfloor h \rfloor} + (h - - \lfloor h \rfloor) (x_{\lfloor h \rfloor + 1} - x_{\lfloor h - * \rfloor}) \\ - * &minLimit = (2/3)/(N+1/3) \\ - * &maxLimit = (N-1/3)/(N+1/3) \\ - * \end{align}\) - *

- * As per Ref [2,3] this approach is most recommended as it provides - * an approximate median-unbiased estimate regardless of distribution. - */ - R_8("R-8") { - @Override - protected double index(final double p, final int length) { - final double minLimit = 2 * (1d / 3) / (length + 1d / 3); - final double maxLimit = - (length - 1d / 3) / (length + 1d / 3); - return Double.compare(p, minLimit) < 0 ? 0 : - Double.compare(p, maxLimit) >= 0 ? length : - (length + 1d / 3) * p + 1d / 3; - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - - /** - * The method R_9 has the following formulae for index and estimates.
- * \( \begin{align} - * &index = (N + 1/4)p + 3/8\\ - * &estimate = x_{\lfloor h \rfloor} + (h - - \lfloor h \rfloor) (x_{\lfloor h \rfloor + 1} - x_{\lfloor h - * \rfloor}) \\ - * &minLimit = (5/8)/(N+1/4) \\ - * &maxLimit = (N-3/8)/(N+1/4) \\ - * \end{align}\) - */ - R_9("R-9") { - @Override - protected double index(final double p, final int length) { - final double minLimit = 5d/8 / (length + 0.25); - final double maxLimit = (length - 3d/8) / (length + 0.25); - return Double.compare(p, minLimit) < 0 ? 0 : - Double.compare(p, maxLimit) >= 0 ? length : - (length + 0.25) * p + 3d/8; - } - @Override - public double evaluate(final double[] work, final double[] sampleWeights, - final double p) { - throw new MathIllegalArgumentException(LocalizedFormats.UNSUPPORTED_OPERATION); - } - }, - ; - - /** Simple name such as R-1, R-2 corresponding to those in wikipedia. */ - private final String name; - - /** - * Constructor. - * - * @param type name of estimation type as per wikipedia - */ - EstimationType(final String type) { - this.name = type; - } - - /** - * Finds the index of array that can be used as starting index to - * {@link #estimate(double[], int[], double, int, KthSelector) estimate} - * percentile. The calculation of index calculation is specific to each - * {@link EstimationType}. - * - * @param p the pth quantile - * @param length the total number of array elements in the work array - * @return a computed real valued index as explained in the wikipedia - */ - protected abstract double index(double p, int length); - - /** - * Estimation based on Kth selection. This may be overridden - * in specific enums to compute slightly different estimations. - * - * @param work array of numbers to be used for finding the percentile - * @param pos indicated positional index prior computed from calling - * {@link #index(double, int)} - * @param pivotsHeap an earlier populated cache if exists; will be used - * @param length size of array considered - * @param selector a {@link KthSelector} used for pivoting during search - * @return estimated percentile - */ - protected double estimate(final double[] work, final int[] pivotsHeap, - final double pos, final int length, - final KthSelector selector) { - - final double fpos = JdkMath.floor(pos); - final int intPos = (int) fpos; - final double dif = pos - fpos; - - if (pos < 1) { - return selector.select(work, pivotsHeap, 0); - } - if (pos >= length) { - return selector.select(work, pivotsHeap, length - 1); - } - - final double lower = selector.select(work, pivotsHeap, intPos - 1); - final double upper = selector.select(work, pivotsHeap, intPos); - return lower + dif * (upper - lower); - } - - /** - * Evaluate method to compute the percentile for a given bounded array - * using earlier computed pivots heap.
- * This basically calls the {@link #index(double, int) index} and then - * {@link #estimate(double[], int[], double, int, KthSelector) estimate} - * functions to return the estimated percentile value. - * - * @param work array of numbers to be used for finding the percentile. - * Cannot be {@code null}. - * @param pivotsHeap a prior cached heap which can speed up estimation - * @param p the pth quantile to be computed - * @param selector a {@link KthSelector} used for pivoting during search - * @return estimated percentile - * @throws OutOfRangeException if p is out of range - */ - protected double evaluate(final double[] work, final int[] pivotsHeap, final double p, - final KthSelector selector) { - NullArgumentException.check(work); - if (p > 100 || p <= 0) { - throw new OutOfRangeException(LocalizedFormats.OUT_OF_BOUNDS_QUANTILE_VALUE, - p, 0, 100); - } - return estimate(work, pivotsHeap, index(p/100d, work.length), work.length, selector); - } - - /** - * Evaluate method to compute the percentile for a given bounded array. - * This basically calls the {@link #index(double, int) index} and then - * {@link #estimate(double[], int[], double, int, KthSelector) estimate} - * functions to return the estimated percentile value. Please - * note that this method does not make use of cached pivots. - * - * @param work array of numbers to be used for finding the percentile. - * Cannot be {@code null}. - * @param p the pth quantile to be computed - * @return estimated percentile - * @param selector a {@link KthSelector} used for pivoting during search - * @throws OutOfRangeException if length or p is out of range - */ - public double evaluate(final double[] work, final double p, final KthSelector selector) { - return this.evaluate(work, null, p, selector); - } - /** - * Evaluate weighted percentile by estimation rule specified in {@link EstimationType}. - * @param work array of numbers to be used for finding the percentile - * @param sampleWeights the corresponding weights of data in work - * @param p the pth quantile to be computed - * @return estimated weighted percentile - * @throws MathIllegalArgumentException if weighted percentile is not supported by the current estimationType - */ - public abstract double evaluate(double[] work, double[] sampleWeights, - double p); - /** - * Search the interval q*sn locates in. - * @param qsn q*sn, where n refers to the data size - * @param sk the cumulative weights array - * @param lo start position to search qsn - * @param hi end position to search qsn - * @return the index of lower bound qsn locates in - */ - private static int searchSk(double qsn, double[] sk, int lo, int hi) { - if (sk.length == 1) { - return 0; - } - if (hi - lo == 1) { - if (qsn == sk[hi]) { - return hi; - } - return lo; - } else { - int mid = (lo + hi) >>> 1; - if (qsn == sk[mid]) { - return mid; - } else if (qsn > sk[mid]) { - return searchSk(qsn, sk, mid, hi); - } else { - return searchSk(qsn, sk, lo, mid); - } - } - } - /** - * Gets the name of the enum. - * - * @return the name - */ - String getName() { - return name; - } - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PivotingStrategy.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PivotingStrategy.java deleted file mode 100644 index 21905028ef..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PivotingStrategy.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -/** - * A strategy to pick a pivoting index of an array for doing partitioning. - * - * @see MedianOf3PivotingStrategy - * @see RandomPivotingStrategy - * @see CentralPivotingStrategy - * @since 4.0 - */ -public interface PivotingStrategy { - /** - * Find pivot index of the array so that partition and Kth - * element selection can be made. - * @param work data array - * @param begin index of the first element of the slice - * @param end index after the last element of the slice - * @return the index of the pivot element chosen between the - * first and the last element of the array slice - * @throws IllegalArgumentException when indices exceeds range - */ - int pivotIndex(double[] work, int begin, int end); -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/RandomPivotingStrategy.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/RandomPivotingStrategy.java deleted file mode 100644 index 044c7cd416..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/rank/RandomPivotingStrategy.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import org.apache.commons.math4.legacy.core.MathArrays; -import org.apache.commons.rng.RestorableUniformRandomProvider; -import org.apache.commons.rng.simple.RandomSource; - -/** - * A strategy of selecting random index between begin and end indices. - * - * @since 3.4 - */ -public class RandomPivotingStrategy implements PivotingStrategy { - /** Source of randomness. */ - private final RandomSource randomSource; - /** Random generator to use for selecting pivot. */ - private transient RestorableUniformRandomProvider random; - - /** - * Simple constructor. - * - * @param randomSource RNG to use for selecting pivot. - * @param seed Seed for initializing the RNG. - * - * @since 4.0 - */ - public RandomPivotingStrategy(RandomSource randomSource, - long seed) { - this.randomSource = randomSource; - random = randomSource.create(seed); - } - - /** - * {@inheritDoc} - * - * A uniform random pivot selection between begin and end indices. - * - * @return The index corresponding to a random uniformly selected - * value between first and the last indices of the array slice - * @throws org.apache.commons.math4.legacy.exception.MathIllegalArgumentException MathIllegalArgumentException when indices exceeds range - */ - @Override - public int pivotIndex(final double[] work, final int begin, final int end) { - MathArrays.verifyValues(work, begin, end - begin); - return begin + random.nextInt(end - begin - 1); - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/SumOfLogs.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/SumOfLogs.java deleted file mode 100644 index d56d271da6..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/SumOfLogs.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.summary; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.core.jdkmath.JdkMath; -import org.apache.commons.math4.legacy.core.MathArrays; - -/** - * Returns the sum of the natural logs for this collection of values. - *

- * Uses {@link org.apache.commons.math4.core.jdkmath.JdkMath#log(double)} to compute the logs. - * Therefore, - *

    - *
  • If any of values are < 0, the result is NaN.
  • - *
  • If all values are non-negative and less than - * Double.POSITIVE_INFINITY, but at least one value is 0, the - * result is Double.NEGATIVE_INFINITY.
  • - *
  • If both Double.POSITIVE_INFINITY and - * Double.NEGATIVE_INFINITY are among the values, the result is - * NaN.
  • - *
- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class SumOfLogs extends AbstractStorelessUnivariateStatistic { - /** Number of values that have been added. */ - private int n; - - /** - * The currently running value. - */ - private double value; - - /** - * Create a SumOfLogs instance. - */ - public SumOfLogs() { - value = 0d; - n = 0; - } - - /** - * Copy constructor, creates a new {@code SumOfLogs} identical - * to the {@code original}. - * - * @param original the {@code SumOfLogs} instance to copy - * @throws NullArgumentException if original is null - */ - public SumOfLogs(SumOfLogs original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - value += JdkMath.log(d); - n++; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return value; - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return n; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - value = 0d; - n = 0; - } - - /** - * Returns the sum of the natural logs of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. - *

- * Throws MathIllegalArgumentException if the array is null.

- *

- * See {@link SumOfLogs}.

- * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the sum of the natural logs of the values or 0 if - * length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - - double sumLog = Double.NaN; - if (MathArrays.verifyValues(values, begin, length, true)) { - sumLog = 0.0; - for (int i = begin; i < begin + length; i++) { - sumLog += JdkMath.log(values[i]); - } - } - return sumLog; - } - - /** - * {@inheritDoc} - */ - @Override - public SumOfLogs copy() { - SumOfLogs result = new SumOfLogs(); - // No try-catch or advertised exception here because args are valid - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source SumOfLogs to copy - * @param dest SumOfLogs to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(SumOfLogs source, SumOfLogs dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.n = source.n; - dest.value = source.value; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/SumOfSquares.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/SumOfSquares.java deleted file mode 100644 index 9c28aa7134..0000000000 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/SumOfSquares.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.summary; - -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.legacy.core.MathArrays; - -/** - * Returns the sum of the squares of the available values. - *

- * If there are no values in the dataset, then 0 is returned. - * If any of the values are - * NaN, then NaN is returned.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

- */ -public class SumOfSquares extends AbstractStorelessUnivariateStatistic { - /** Number of values that have been added. */ - private long n; - - /** - * The currently running sumSq. - */ - private double value; - - /** - * Create a SumOfSquares instance. - */ - public SumOfSquares() { - n = 0; - value = 0; - } - - /** - * Copy constructor, creates a new {@code SumOfSquares} identical - * to the {@code original}. - * - * @param original the {@code SumOfSquares} instance to copy - * @throws NullArgumentException if original is null - */ - public SumOfSquares(SumOfSquares original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - value += d * d; - n++; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return value; - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return n; - } - - /** - * {@inheritDoc} - */ - @Override - public void clear() { - value = 0; - n = 0; - } - - /** - * Returns the sum of the squares of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. - *

- * Throws MathIllegalArgumentException if the array is null.

- * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the sum of the squares of the values or 0 if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid - */ - @Override - public double evaluate(final double[] values,final int begin, final int length) - throws MathIllegalArgumentException { - - double sumSq = Double.NaN; - if (MathArrays.verifyValues(values, begin, length, true)) { - sumSq = 0.0; - for (int i = begin; i < begin + length; i++) { - sumSq += values[i] * values[i]; - } - } - return sumSq; - } - - /** - * {@inheritDoc} - */ - @Override - public SumOfSquares copy() { - SumOfSquares result = new SumOfSquares(); - // no try-catch or advertised exception here because args are valid - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source SumOfSquares to copy - * @param dest SumOfSquares to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(SumOfSquares source, SumOfSquares dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.n = source.n; - dest.value = source.value; - } -} diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/Product.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/WeightedProduct.java similarity index 55% rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/Product.java rename to commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/WeightedProduct.java index 88c8c4b16e..d78c305504 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/Product.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/WeightedProduct.java @@ -16,117 +16,39 @@ */ package org.apache.commons.math4.legacy.stat.descriptive.summary; -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; -import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation; import org.apache.commons.math4.core.jdkmath.JdkMath; import org.apache.commons.math4.legacy.core.MathArrays; +import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; +import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation; /** - * Returns the product of the available values. + * Returns the weighted product of the available values. *

* If there are no values in the dataset, then 1 is returned. - * If any of the values are + * If any of the values are * NaN, then NaN is returned.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

*/ -public class Product extends AbstractStorelessUnivariateStatistic implements WeightedEvaluation { - /**The number of values that have been added. */ - private long n; - - /** - * The current Running Product. - */ - private double value; - - /** - * Create a Product instance. - */ - public Product() { - n = 0; - value = 1; - } - - /** - * Copy constructor, creates a new {@code Product} identical - * to the {@code original}. - * - * @param original the {@code Product} instance to copy - * @throws NullArgumentException if original is null - */ - public Product(Product original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - value *= d; - n++; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return value; - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return n; - } +public final class WeightedProduct implements WeightedEvaluation { + /** An instance. */ + private static final WeightedProduct INSTANCE = new WeightedProduct(); - /** - * {@inheritDoc} - */ - @Override - public void clear() { - value = 1; - n = 0; + /** Create an instance. */ + private WeightedProduct() { + // Do nothing } /** - * Returns the product of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray - * is empty. - *

- * Throws MathIllegalArgumentException if the array is null.

+ * Gets an instance. * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the product of the values or 1 if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid + * @return an instance */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - double product = Double.NaN; - if (MathArrays.verifyValues(values, begin, length, true)) { - product = 1.0; - for (int i = begin; i < begin + length; i++) { - product *= values[i]; - } - } - return product; + public static WeightedProduct getInstance() { + return INSTANCE; } /** *

Returns the weighted product of the entries in the specified portion of - * the input array, or Double.NaN if the designated subarray + * the input array, or 1 if the designated subarray * is empty.

* *

Throws MathIllegalArgumentException if any of the following are true: @@ -193,31 +115,4 @@ public double evaluate(final double[] values, final double[] weights, public double evaluate(final double[] values, final double[] weights) throws MathIllegalArgumentException { return evaluate(values, weights, 0, values.length); } - - /** - * {@inheritDoc} - */ - @Override - public Product copy() { - Product result = new Product(); - // No try-catch or advertised exception because args are valid - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source Product to copy - * @param dest Product to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(Product source, Product dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.n = source.n; - dest.value = source.value; - } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/Sum.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/WeightedSum.java similarity index 50% rename from commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/Sum.java rename to commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/WeightedSum.java index 2522652f1b..45819d0a0e 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/Sum.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/descriptive/summary/WeightedSum.java @@ -17,110 +17,32 @@ package org.apache.commons.math4.legacy.stat.descriptive.summary; import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.AbstractStorelessUnivariateStatistic; +import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation; import org.apache.commons.math4.legacy.core.MathArrays; - /** - * Returns the sum of the available values. + * Returns the weighted sum of the available values. *

* If there are no values in the dataset, then 0 is returned. * If any of the values are - * NaN, then NaN is returned.

- *

- * Note that this implementation is not synchronized. If - * multiple threads access an instance of this class concurrently, and at least - * one of the threads invokes the increment() or - * clear() method, it must be synchronized externally.

+ * {@code NaN}, then {@code NaN} is returned. */ -public class Sum extends AbstractStorelessUnivariateStatistic { - /** */ - private long n; - - /** - * The currently running sum. - */ - private double value; - - /** - * Create a Sum instance. - */ - public Sum() { - n = 0; - value = 0; - } - - /** - * Copy constructor, creates a new {@code Sum} identical - * to the {@code original}. - * - * @param original the {@code Sum} instance to copy - * @throws NullArgumentException if original is null - */ - public Sum(Sum original) throws NullArgumentException { - copy(original, this); - } - - /** - * {@inheritDoc} - */ - @Override - public void increment(final double d) { - value += d; - n++; - } - - /** - * {@inheritDoc} - */ - @Override - public double getResult() { - return value; - } - - /** - * {@inheritDoc} - */ - @Override - public long getN() { - return n; - } +public final class WeightedSum implements WeightedEvaluation { + /** An instance. */ + private static final WeightedSum INSTANCE = new WeightedSum(); - /** - * {@inheritDoc} - */ - @Override - public void clear() { - value = 0; - n = 0; + /** Create an instance. */ + private WeightedSum() { + // Do nothing } /** - * The sum of the entries in the specified portion of the input array, - * or 0 if the designated subarray is empty. - *

- * Throws MathIllegalArgumentException if the array is null.

+ * Gets an instance. * - * @param values the input array - * @param begin index of the first array element to include - * @param length the number of elements to include - * @return the sum of the values or 0 if length = 0 - * @throws MathIllegalArgumentException if the array is null or the array index - * parameters are not valid + * @return an instance */ - @Override - public double evaluate(final double[] values, final int begin, final int length) - throws MathIllegalArgumentException { - - double sum = Double.NaN; - if (MathArrays.verifyValues(values, begin, length, true)) { - sum = 0.0; - for (int i = begin; i < begin + length; i++) { - sum += values[i]; - } - } - return sum; + public static WeightedSum getInstance() { + return INSTANCE; } /** @@ -148,16 +70,16 @@ public double evaluate(final double[] values, final int begin, final int length) * @param length the number of elements to include * @return the sum of the values or 0 if length = 0 * @throws MathIllegalArgumentException if the parameters are not valid - * @since 2.1 */ + @Override public double evaluate(final double[] values, final double[] weights, final int begin, final int length) throws MathIllegalArgumentException { - double sum = Double.NaN; - if (MathArrays.verifyValues(values, weights, begin, length, true)) { - sum = 0.0; - for (int i = begin; i < begin + length; i++) { - sum += values[i] * weights[i]; - } + // Zero length is allowed + MathArrays.verifyValues(values, weights, begin, length, true); + double sum = 0; + final int end = begin + length; + for (int i = begin; i < end; i++) { + sum += values[i] * weights[i]; } return sum; } @@ -180,38 +102,11 @@ public double evaluate(final double[] values, final double[] weights, * * @param values the input array * @param weights the weights array - * @return the sum of the values or Double.NaN if length = 0 + * @return the sum of the values or 0 if length = 0 * @throws MathIllegalArgumentException if the parameters are not valid - * @since 2.1 */ + @Override public double evaluate(final double[] values, final double[] weights) throws MathIllegalArgumentException { return evaluate(values, weights, 0, values.length); } - - /** - * {@inheritDoc} - */ - @Override - public Sum copy() { - Sum result = new Sum(); - // No try-catch or advertised exception because args are valid - copy(this, result); - return result; - } - - /** - * Copies source to dest. - *

Neither source nor dest can be null.

- * - * @param source Sum to copy - * @param dest Sum to copy to - * @throws NullArgumentException if either source or dest is null - */ - public static void copy(Sum source, Sum dest) - throws NullArgumentException { - NullArgumentException.check(source); - NullArgumentException.check(dest); - dest.n = source.n; - dest.value = source.value; - } } diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/regression/AbstractMultipleLinearRegression.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/regression/AbstractMultipleLinearRegression.java index c23e7dbc33..727551e10c 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/regression/AbstractMultipleLinearRegression.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/regression/AbstractMultipleLinearRegression.java @@ -27,7 +27,7 @@ import org.apache.commons.math4.legacy.linear.NonSquareMatrixException; import org.apache.commons.math4.legacy.linear.RealMatrix; import org.apache.commons.math4.legacy.linear.RealVector; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; +import org.apache.commons.statistics.descriptive.Variance; import org.apache.commons.math4.core.jdkmath.JdkMath; /** @@ -347,7 +347,7 @@ public double estimateRegressionStandardError() { * @return Y variance */ protected double calculateYVariance() { - return new Variance().evaluate(yVector.toArray()); + return Variance.of(yVector.toArray()).getAsDouble(); } /** diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/regression/OLSMultipleLinearRegression.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/regression/OLSMultipleLinearRegression.java index 6318dc0a7d..123e9570d2 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/regression/OLSMultipleLinearRegression.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/stat/regression/OLSMultipleLinearRegression.java @@ -23,7 +23,7 @@ import org.apache.commons.math4.legacy.linear.RealMatrix; import org.apache.commons.math4.legacy.linear.RealVector; import org.apache.commons.math4.legacy.stat.StatUtils; -import org.apache.commons.math4.legacy.stat.descriptive.moment.SecondMoment; +import org.apache.commons.statistics.descriptive.Mean; /** *

Implements ordinary least squares (OLS) to estimate the parameters of a @@ -161,10 +161,17 @@ public RealMatrix calculateHat() { * @since 2.2 */ public double calculateTotalSumOfSquares() { + final double[] y = getY().toArray(); if (isNoIntercept()) { - return StatUtils.sumSq(getY().toArray()); + return StatUtils.sumSq(y); } else { - return new SecondMoment().evaluate(getY().toArray()); + final double m = Mean.of(y).getAsDouble(); + double s = 0; + for (final double v : y) { + final double d = v - m; + s += d * d; + } + return s; } } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/fitting/MultivariateNormalMixtureExpectationMaximizationTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/fitting/MultivariateNormalMixtureExpectationMaximizationTest.java index 2810364562..ed039b30cf 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/fitting/MultivariateNormalMixtureExpectationMaximizationTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/fitting/MultivariateNormalMixtureExpectationMaximizationTest.java @@ -26,7 +26,6 @@ import org.apache.commons.math4.legacy.exception.DimensionMismatchException; import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException; -import org.apache.commons.math4.legacy.linear.Array2DRowRealMatrix; import org.apache.commons.math4.legacy.linear.RealMatrix; import org.apache.commons.math4.legacy.core.Pair; import org.junit.Assert; @@ -153,24 +152,21 @@ public void testInitialMixture() { {5.090902706507635, 8.68540656355283}, }; - final RealMatrix[] correctCovMats = new Array2DRowRealMatrix[2]; - - correctCovMats[0] = new Array2DRowRealMatrix(new double[][] { - { 4.537422569229048, 3.5266152281729304 }, - { 3.5266152281729304, 6.175448814169779 } }); - - correctCovMats[1] = new Array2DRowRealMatrix( new double[][] { - { 2.886778573963039, 1.5257474543463154 }, - { 1.5257474543463154, 3.3794567673616918 } }); + final double[][][] correctCovMats = new double[][][] { + {{4.537422569229048, 3.5266152281729304}, + {3.5266152281729304, 6.175448814169779}}, + {{2.886778573963039, 1.5257474543463154}, + {1.5257474543463154, 3.3794567673616918}} + }; final MultivariateNormalDistribution[] correctMVNs = new MultivariateNormalDistribution[2]; correctMVNs[0] = new MultivariateNormalDistribution(correctMeans[0], - correctCovMats[0].getData()); + correctCovMats[0]); correctMVNs[1] = new MultivariateNormalDistribution(correctMeans[1], - correctCovMats[1].getData()); + correctCovMats[1]); final MixtureMultivariateNormalDistribution initialMix = MultivariateNormalMixtureExpectationMaximization.estimate(getTestSamples(), 2); @@ -185,7 +181,7 @@ public void testInitialMixture() { Assert.assertArrayEquals(correctMeans[i], means, 0.0); final RealMatrix covMat = component.getValue().getCovariances(); - Assert.assertEquals(correctCovMats[i], covMat); + assertArrayEquals(correctCovMats[i], covMat.getData(), 1e-15); i++; } } @@ -305,6 +301,13 @@ private static void assertFit(double[][] data, int numComponents, } } + private static void assertArrayEquals(double[][] e, double[][] a, double relError) { + Assert.assertEquals("length", e.length, a.length); + for (int i = 0; i < e.length; i++) { + assertArrayEquals(e[i], a[i], relError); + } + } + private static void assertArrayEquals(double[] e, double[] a, double relError) { Assert.assertEquals("length", e.length, a.length); for (int i = 0; i < e.length; i++) { diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/StatUtilsTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/StatUtilsTest.java index 41257c7ed4..b5a8dcd5c8 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/StatUtilsTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/StatUtilsTest.java @@ -25,6 +25,7 @@ import org.apache.commons.numbers.core.Precision; import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; /** * Test cases for the {@link StatUtils} class. @@ -51,7 +52,6 @@ public void testStats() { Assert.assertEquals("sum", SUM, StatUtils.sum(values), TOLERANCE); Assert.assertEquals("sumsq", SUMSQ, StatUtils.sumSq(values), TOLERANCE); Assert.assertEquals("var", VAR, StatUtils.variance(values), TOLERANCE); - Assert.assertEquals("var with mean", VAR, StatUtils.variance(values, MEAN), TOLERANCE); Assert.assertEquals("mean", MEAN, StatUtils.mean(values), TOLERANCE); Assert.assertEquals("min", MIN, StatUtils.min(values), TOLERANCE); Assert.assertEquals("max", MAX, StatUtils.max(values), TOLERANCE); @@ -109,6 +109,41 @@ public void testArrayIndexConditions() { } } + @Test + public void testSum() { + double[] x = null; + + // test null + try { + StatUtils.sum(x); + Assert.fail("null is not a valid data array."); + } catch (NullArgumentException ex) { + // success + } + + try { + StatUtils.sum(x, 0, 4); + Assert.fail("null is not a valid data array."); + } catch (NullArgumentException ex) { + // success + } + + // test empty + x = new double[] {}; + TestUtils.assertEquals(Double.NaN, StatUtils.sum(x), TOLERANCE); + TestUtils.assertEquals(Double.NaN, StatUtils.sum(x, 0, 0), TOLERANCE); + + // test one + x = new double[] {TWO}; + TestUtils.assertEquals(2, StatUtils.sum(x), TOLERANCE); + TestUtils.assertEquals(2, StatUtils.sum(x, 0, 1), TOLERANCE); + + // test many + x = new double[] {ONE, TWO, TWO, THREE}; + TestUtils.assertEquals(8, StatUtils.sum(x), TOLERANCE); + TestUtils.assertEquals(4, StatUtils.sum(x, 1, 2), TOLERANCE); + } + @Test public void testSumSq() { double[] x = null; @@ -130,8 +165,8 @@ public void testSumSq() { // test empty x = new double[] {}; - TestUtils.assertEquals(0, StatUtils.sumSq(x), TOLERANCE); - TestUtils.assertEquals(0, StatUtils.sumSq(x, 0, 0), TOLERANCE); + TestUtils.assertEquals(Double.NaN, StatUtils.sumSq(x), TOLERANCE); + TestUtils.assertEquals(Double.NaN, StatUtils.sumSq(x, 0, 0), TOLERANCE); // test one x = new double[] {TWO}; @@ -165,8 +200,8 @@ public void testProduct() { // test empty x = new double[] {}; - TestUtils.assertEquals(1, StatUtils.product(x), TOLERANCE); - TestUtils.assertEquals(1, StatUtils.product(x, 0, 0), TOLERANCE); + TestUtils.assertEquals(Double.NaN, StatUtils.product(x), TOLERANCE); + TestUtils.assertEquals(Double.NaN, StatUtils.product(x, 0, 0), TOLERANCE); // test one x = new double[] {TWO}; @@ -200,8 +235,8 @@ public void testSumLog() { // test empty x = new double[] {}; - TestUtils.assertEquals(0, StatUtils.sumLog(x), TOLERANCE); - TestUtils.assertEquals(0, StatUtils.sumLog(x, 0, 0), TOLERANCE); + TestUtils.assertEquals(Double.NaN, StatUtils.sumLog(x), TOLERANCE); + TestUtils.assertEquals(Double.NaN, StatUtils.sumLog(x, 0, 0), TOLERANCE); // test one x = new double[] {TWO}; @@ -227,14 +262,17 @@ public void testMean() { // test empty x = new double[] {}; + TestUtils.assertEquals(Double.NaN, StatUtils.mean(x), TOLERANCE); TestUtils.assertEquals(Double.NaN, StatUtils.mean(x, 0, 0), TOLERANCE); // test one x = new double[] {TWO}; + TestUtils.assertEquals(TWO, StatUtils.mean(x), TOLERANCE); TestUtils.assertEquals(TWO, StatUtils.mean(x, 0, 1), TOLERANCE); // test many x = new double[] {ONE, TWO, TWO, THREE}; + TestUtils.assertEquals(2, StatUtils.mean(x), TOLERANCE); TestUtils.assertEquals(2.5, StatUtils.mean(x, 2, 2), TOLERANCE); } @@ -251,19 +289,18 @@ public void testVariance() { // test empty x = new double[] {}; + TestUtils.assertEquals(Double.NaN, StatUtils.variance(x), TOLERANCE); TestUtils.assertEquals(Double.NaN, StatUtils.variance(x, 0, 0), TOLERANCE); // test one x = new double[] {TWO}; + TestUtils.assertEquals(0.0, StatUtils.variance(x), TOLERANCE); TestUtils.assertEquals(0.0, StatUtils.variance(x, 0, 1), TOLERANCE); // test many x = new double[] {ONE, TWO, TWO, THREE}; + TestUtils.assertEquals(2.0 / 3, StatUtils.variance(x), TOLERANCE); TestUtils.assertEquals(0.5, StatUtils.variance(x, 2, 2), TOLERANCE); - - // test precomputed mean - x = new double[] {ONE, TWO, TWO, THREE}; - TestUtils.assertEquals(0.5, StatUtils.variance(x,2.5, 2, 2), TOLERANCE); } @Test @@ -279,19 +316,18 @@ public void testPopulationVariance() { // test empty x = new double[] {}; + TestUtils.assertEquals(Double.NaN, StatUtils.populationVariance(x), TOLERANCE); TestUtils.assertEquals(Double.NaN, StatUtils.populationVariance(x, 0, 0), TOLERANCE); // test one x = new double[] {TWO}; TestUtils.assertEquals(0.0, StatUtils.populationVariance(x, 0, 1), TOLERANCE); + TestUtils.assertEquals(0.0, StatUtils.populationVariance(x, 0, 1), TOLERANCE); // test many x = new double[] {ONE, TWO, TWO, THREE}; + TestUtils.assertEquals(0.5, StatUtils.populationVariance(x), TOLERANCE); TestUtils.assertEquals(0.25, StatUtils.populationVariance(x, 0, 2), TOLERANCE); - - // test precomputed mean - x = new double[] {ONE, TWO, TWO, THREE}; - TestUtils.assertEquals(0.25, StatUtils.populationVariance(x, 2.5, 2, 2), TOLERANCE); } @@ -308,27 +344,32 @@ public void testMax() { // test empty x = new double[] {}; + TestUtils.assertEquals(Double.NaN, StatUtils.max(x), TOLERANCE); TestUtils.assertEquals(Double.NaN, StatUtils.max(x, 0, 0), TOLERANCE); // test one x = new double[] {TWO}; + TestUtils.assertEquals(TWO, StatUtils.max(x), TOLERANCE); TestUtils.assertEquals(TWO, StatUtils.max(x, 0, 1), TOLERANCE); // test many x = new double[] {ONE, TWO, TWO, THREE}; - TestUtils.assertEquals(THREE, StatUtils.max(x, 1, 3), TOLERANCE); - - // test first nan is ignored - x = new double[] {NAN, TWO, THREE}; TestUtils.assertEquals(THREE, StatUtils.max(x), TOLERANCE); + TestUtils.assertEquals(THREE, StatUtils.max(x, 1, 3), TOLERANCE); - // test middle nan is ignored - x = new double[] {ONE, NAN, THREE}; - TestUtils.assertEquals(THREE, StatUtils.max(x), TOLERANCE); + // Legacy behaviour - // test last nan is ignored - x = new double[] {ONE, TWO, NAN}; - TestUtils.assertEquals(TWO, StatUtils.max(x), TOLERANCE); +// // test first nan is ignored +// x = new double[] {NAN, TWO, THREE}; +// TestUtils.assertEquals(THREE, StatUtils.max(x), TOLERANCE); +// +// // test middle nan is ignored +// x = new double[] {ONE, NAN, THREE}; +// TestUtils.assertEquals(THREE, StatUtils.max(x), TOLERANCE); +// +// // test last nan is ignored +// x = new double[] {ONE, TWO, NAN}; +// TestUtils.assertEquals(TWO, StatUtils.max(x), TOLERANCE); // test all nan returns nan x = new double[] {NAN, NAN, NAN}; @@ -348,27 +389,32 @@ public void testMin() { // test empty x = new double[] {}; + TestUtils.assertEquals(Double.NaN, StatUtils.min(x), TOLERANCE); TestUtils.assertEquals(Double.NaN, StatUtils.min(x, 0, 0), TOLERANCE); // test one x = new double[] {TWO}; + TestUtils.assertEquals(TWO, StatUtils.min(x), TOLERANCE); TestUtils.assertEquals(TWO, StatUtils.min(x, 0, 1), TOLERANCE); // test many x = new double[] {ONE, TWO, TWO, THREE}; + TestUtils.assertEquals(ONE, StatUtils.min(x), TOLERANCE); TestUtils.assertEquals(TWO, StatUtils.min(x, 1, 3), TOLERANCE); - // test first nan is ignored - x = new double[] {NAN, TWO, THREE}; - TestUtils.assertEquals(TWO, StatUtils.min(x), TOLERANCE); - - // test middle nan is ignored - x = new double[] {ONE, NAN, THREE}; - TestUtils.assertEquals(ONE, StatUtils.min(x), TOLERANCE); + // Legacy behaviour - // test last nan is ignored - x = new double[] {ONE, TWO, NAN}; - TestUtils.assertEquals(ONE, StatUtils.min(x), TOLERANCE); +// // test first nan is ignored +// x = new double[] {NAN, TWO, THREE}; +// TestUtils.assertEquals(TWO, StatUtils.min(x), TOLERANCE); +// +// // test middle nan is ignored +// x = new double[] {ONE, NAN, THREE}; +// TestUtils.assertEquals(ONE, StatUtils.min(x), TOLERANCE); +// +// // test last nan is ignored +// x = new double[] {ONE, TWO, NAN}; +// TestUtils.assertEquals(ONE, StatUtils.min(x), TOLERANCE); // test all nan returns nan x = new double[] {NAN, NAN, NAN}; @@ -427,6 +473,13 @@ public void testDifferenceStats() { } catch (MathIllegalArgumentException ex) { // expected } + try { + double[] empty = {}; + StatUtils.meanDifference(empty, empty); + Assert.fail("Expecting MathIllegalArgumentException"); + } catch (MathIllegalArgumentException ex) { + // expected + } try { StatUtils.varianceDifference(sample1, small, meanDifference); Assert.fail("Expecting MathIllegalArgumentException"); @@ -544,5 +597,15 @@ public void testMode() { } catch (NullArgumentException ex) { // Expected } + + // Range tests + Assertions.assertArrayEquals(new double[] {0}, StatUtils.mode(singleMode, 0, 4)); + Assertions.assertArrayEquals(new double[] {0, 2, 7, 11}, StatUtils.mode(singleMode, 2, 4)); + Assertions.assertArrayEquals(new double[] {0}, StatUtils.mode(twoMode, 0, 4)); + Assertions.assertArrayEquals(new double[] {0, 2}, StatUtils.mode(twoMode, 0, 5)); + Assertions.assertThrows(NullArgumentException.class, () -> StatUtils.mode(null, 0, 5)); + Assertions.assertThrows(MathIllegalArgumentException.class, () -> StatUtils.mode(singleMode, -1, 1)); + Assertions.assertThrows(MathIllegalArgumentException.class, () -> StatUtils.mode(singleMode, 0, -1)); + Assertions.assertThrows(MathIllegalArgumentException.class, () -> StatUtils.mode(singleMode, 0, 100)); } } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/correlation/CovarianceTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/correlation/CovarianceTest.java index 5fc107d55a..099aceb1ee 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/correlation/CovarianceTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/correlation/CovarianceTest.java @@ -21,7 +21,6 @@ import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; import org.apache.commons.math4.legacy.linear.Array2DRowRealMatrix; import org.apache.commons.math4.legacy.linear.RealMatrix; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; import org.junit.Assert; import org.junit.Test; @@ -204,9 +203,9 @@ public void testConsistency() { final RealMatrix covarianceMatrix = new Covariance(matrix).getCovarianceMatrix(); // Variances on the diagonal - Variance variance = new Variance(); for (int i = 0; i < 5; i++) { - Assert.assertEquals(variance.evaluate(matrix.getColumn(i)), covarianceMatrix.getEntry(i,i), 10E-14); + Assert.assertEquals(org.apache.commons.statistics.descriptive.Variance.of(matrix.getColumn(i)).getAsDouble(), + covarianceMatrix.getEntry(i,i), 10E-14); } // Symmetry, column-consistency @@ -220,7 +219,7 @@ public void testConsistency() { repeatedColumns.setColumnMatrix(i, matrix.getColumnMatrix(0)); } RealMatrix repeatedCovarianceMatrix = new Covariance(repeatedColumns).getCovarianceMatrix(); - double columnVariance = variance.evaluate(matrix.getColumn(0)); + double columnVariance = org.apache.commons.statistics.descriptive.Variance.of(matrix.getColumn(0)).getAsDouble(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { Assert.assertEquals(columnVariance, repeatedCovarianceMatrix.getEntry(i, j), 10E-14); diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/AggregateSummaryStatisticsTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/AggregateSummaryStatisticsTest.java index ce640751e9..4e971947ff 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/AggregateSummaryStatisticsTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/AggregateSummaryStatisticsTest.java @@ -117,9 +117,23 @@ public void testAggregationConsistency() { * Note that guaranteed success of this comparison depends on the * fact that gets values in exactly the same order * as . - * */ - Assert.assertEquals(totalStats.getSummary(), aggregate.getSummary()); + assertEquals(totalStats.getSummary(), aggregate.getSummary()); + } + + private static void assertEquals(StatisticalSummary summary, StatisticalSummary summary2) { + Assert.assertArrayEquals(toArray(summary), toArray(summary2), 0); + } + + private static double[] toArray(StatisticalSummary summary) { + return new double[] { + summary.getMean(), + summary.getVariance(), + summary.getN(), + summary.getMax(), + summary.getMin(), + summary.getSum(), + }; } /** diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/DescriptiveStatisticsTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/DescriptiveStatisticsTest.java index 4dcc278970..c47e7f57f0 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/DescriptiveStatisticsTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/DescriptiveStatisticsTest.java @@ -16,23 +16,19 @@ */ package org.apache.commons.math4.legacy.stat.descriptive; +import java.util.Arrays; import java.util.Locale; - +import org.apache.commons.math4.core.jdkmath.JdkMath; import org.apache.commons.math4.legacy.TestUtils; import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Max; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Min; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile; -import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum; -import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares; +import org.apache.commons.math4.legacy.stat.StatUtils; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Percentile; import org.apache.commons.numbers.core.Precision; import org.apache.commons.rng.UniformRandomProvider; import org.apache.commons.rng.simple.RandomSource; import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; /** * Test cases for the {@link DescriptiveStatistics} class. @@ -44,6 +40,25 @@ protected DescriptiveStatistics createDescriptiveStatistics() { return new DescriptiveStatistics(); } + @Test + public void testEmpty() { + final DescriptiveStatistics stats = createDescriptiveStatistics(); + + final double[] x = {}; + Assertions.assertEquals(StatUtils.mean(x), stats.getMean()); + Assertions.assertEquals(StatUtils.geometricMean(x), stats.getGeometricMean()); + final double v = StatUtils.variance(x); + Assertions.assertEquals(v, stats.getVariance()); + Assertions.assertEquals(JdkMath.sqrt(v), stats.getStandardDeviation()); + Assertions.assertEquals(Double.NaN, stats.getQuadraticMean()); + Assertions.assertEquals(Double.NaN, stats.getKurtosis()); + Assertions.assertEquals(Double.NaN, stats.getSkewness()); + Assertions.assertEquals(StatUtils.max(x), stats.getMax()); + Assertions.assertEquals(StatUtils.min(x), stats.getMin()); + Assertions.assertEquals(StatUtils.sum(x), stats.getSum()); + Assertions.assertEquals(StatUtils.sumSq(x), stats.getSumsq()); + } + @Test public void testSetterInjection() { DescriptiveStatistics stats = createDescriptiveStatistics(); @@ -236,30 +251,29 @@ public void testSummaryConsistency() { final int windowSize = 5; dstats.setWindowSize(windowSize); final double tol = 1E-12; - for (int i = 0; i < 20; i++) { - dstats.addValue(i); + final int n = 20; + for (int i = 0; i <= n; i++) { + // Test with NaN to ensure updated Min/Max behaviour is consistent + double x = i == n ? Double.NaN : i; + dstats.addValue(x); sstats.clear(); double[] values = dstats.getValues(); for (int j = 0; j < values.length; j++) { sstats.addValue(values[j]); } TestUtils.assertEquals(dstats.getMean(), sstats.getMean(), tol); - TestUtils.assertEquals(new Mean().evaluate(values), dstats.getMean(), tol); + TestUtils.assertEquals(org.apache.commons.statistics.descriptive.Mean.of(values).getAsDouble(), dstats.getMean(), tol); TestUtils.assertEquals(dstats.getMax(), sstats.getMax(), tol); - TestUtils.assertEquals(new Max().evaluate(values), dstats.getMax(), tol); - TestUtils.assertEquals(dstats.getGeometricMean(), sstats.getGeometricMean(), tol); - TestUtils.assertEquals(new GeometricMean().evaluate(values), dstats.getGeometricMean(), tol); + TestUtils.assertEquals(Arrays.stream(values).max().orElse(-1.23), dstats.getMax(), tol); + TestUtils.assertEquals(org.apache.commons.statistics.descriptive.GeometricMean.of(values).getAsDouble(), dstats.getGeometricMean(), tol); TestUtils.assertEquals(dstats.getMin(), sstats.getMin(), tol); - TestUtils.assertEquals(new Min().evaluate(values), dstats.getMin(), tol); + TestUtils.assertEquals(Arrays.stream(values).min().orElse(-1.23), dstats.getMin(), tol); TestUtils.assertEquals(dstats.getStandardDeviation(), sstats.getStandardDeviation(), tol); TestUtils.assertEquals(dstats.getVariance(), sstats.getVariance(), tol); - TestUtils.assertEquals(new Variance().evaluate(values), dstats.getVariance(), tol); + TestUtils.assertEquals(org.apache.commons.statistics.descriptive.Variance.of(values).getAsDouble(), dstats.getVariance(), tol); TestUtils.assertEquals(dstats.getSum(), sstats.getSum(), tol); - TestUtils.assertEquals(new Sum().evaluate(values), dstats.getSum(), tol); - TestUtils.assertEquals(dstats.getSumsq(), sstats.getSumsq(), tol); - TestUtils.assertEquals(new SumOfSquares().evaluate(values), dstats.getSumsq(), tol); - TestUtils.assertEquals(dstats.getPopulationVariance(), sstats.getPopulationVariance(), tol); - TestUtils.assertEquals(new Variance(false).evaluate(values), dstats.getPopulationVariance(), tol); + TestUtils.assertEquals(org.apache.commons.statistics.descriptive.Sum.of(values).getAsDouble(), dstats.getSum(), tol); + TestUtils.assertEquals(org.apache.commons.statistics.descriptive.SumOfSquares.of(values).getAsDouble(), dstats.getSumsq(), tol); } } @@ -399,7 +413,7 @@ private Double[] generateInitialDoubleArray(int size) { // Test UnivariateStatistics impls for setter injection tests /** - * A new way to compute the mean + * A new way to compute the mean. */ static class DeepMean implements UnivariateStatistic { @@ -419,11 +433,13 @@ public UnivariateStatistic copy() { } /** - * Test percentile implementation - wraps a Percentile + * Test percentile implementation - wraps a Percentile. */ static class GoodPercentile implements UnivariateStatistic { - private final Percentile percentile = new Percentile(); + private final Percentile percentile = Percentile.create(50); + private double q; public void setQuantile(double quantile) { + q = quantile; percentile.setQuantile(quantile); } @Override @@ -437,48 +453,53 @@ public double evaluate(double[] values) { @Override public UnivariateStatistic copy() { GoodPercentile result = new GoodPercentile(); - result.setQuantile(percentile.getQuantile()); + result.setQuantile(q); return result; } } /** - * Test percentile subclass - another "new math" impl - * Always returns currently set quantile + * Test percentile subclass - another "new math" impl. + * Always returns currently set quantile. */ - static class SubPercentile extends Percentile { + static class SubPercentile implements UnivariateStatistic { + private double q; + public void setQuantile(double quantile) { + q = quantile; + } @Override public double evaluate(double[] values, int begin, int length) { - return getQuantile(); + return q; } @Override public double evaluate(double[] values) { - return getQuantile(); + return q; } - private static final long serialVersionUID = 8040701391045914979L; @Override - public Percentile copy() { + public UnivariateStatistic copy() { SubPercentile result = new SubPercentile(); + result.q = this.q; return result; } } /** - * "Bad" test percentile implementation - no setQuantile + * "Bad" test percentile implementation - no setQuantile method. */ static class BadPercentile implements UnivariateStatistic { - private final Percentile percentile = new Percentile(); @Override public double evaluate(double[] values, int begin, int length) { - return percentile.evaluate(values, begin, length); + // Not used + return Double.NaN; } @Override public double evaluate(double[] values) { - return percentile.evaluate(values); + // Not used + return Double.NaN; } @Override public UnivariateStatistic copy() { - return new BadPercentile(); + return this; } } } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/MultivariateSummaryStatisticsTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/MultivariateSummaryStatisticsTest.java index 60cc597884..a34a9e6ce0 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/MultivariateSummaryStatisticsTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/MultivariateSummaryStatisticsTest.java @@ -16,15 +16,15 @@ */ package org.apache.commons.math4.legacy.stat.descriptive; - import java.util.Locale; import org.apache.commons.math4.legacy.TestUtils; import org.apache.commons.math4.legacy.exception.DimensionMismatchException; import org.apache.commons.math4.legacy.exception.MathIllegalStateException; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessMean; import org.apache.commons.math4.core.jdkmath.JdkMath; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.junit.Assert; /** @@ -55,7 +55,7 @@ public void testSetterInjection() { Assert.assertEquals(6, u.getMean()[1], 1E-14); u.clear(); u.setMeanImpl(new StorelessUnivariateStatistic[] { - new Mean(), new Mean() + StorelessMean.create(), StorelessMean.create() }); // OK after clear u.addValue(new double[] { 1, 2 }); u.addValue(new double[] { 3, 4 }); @@ -241,7 +241,7 @@ public void testN0andN1Conditions() { public void testNaNContracts() { MultivariateSummaryStatistics u = createMultivariateSummaryStatistics(1, true); Assert.assertTrue(Double.isNaN(u.getMean()[0])); - Assert.assertTrue(Double.isNaN(u.getMin()[0])); + Assertions.assertEquals(Double.POSITIVE_INFINITY, u.getMin()[0]); Assert.assertTrue(Double.isNaN(u.getStandardDeviation()[0])); Assert.assertTrue(Double.isNaN(u.getGeometricMean()[0])); @@ -251,46 +251,4 @@ public void testNaNContracts() { Assert.assertFalse(Double.isNaN(u.getStandardDeviation()[0])); Assert.assertFalse(Double.isNaN(u.getGeometricMean()[0])); } - - @Test - public void testEqualsAndHashCode() { - MultivariateSummaryStatistics u = createMultivariateSummaryStatistics(2, true); - MultivariateSummaryStatistics t = null; - int emptyHash = u.hashCode(); - Assert.assertEquals(u, u); - Assert.assertNotEquals(u, t); - Assert.assertFalse(u.equals(Double.valueOf(0))); - t = createMultivariateSummaryStatistics(2, true); - Assert.assertEquals(t, u); - Assert.assertEquals(u, t); - Assert.assertEquals(emptyHash, t.hashCode()); - - // Add some data to u - u.addValue(new double[] { 2d, 1d }); - u.addValue(new double[] { 1d, 1d }); - u.addValue(new double[] { 3d, 1d }); - u.addValue(new double[] { 4d, 1d }); - u.addValue(new double[] { 5d, 1d }); - Assert.assertFalse(t.equals(u)); - Assert.assertFalse(u.equals(t)); - Assert.assertTrue(u.hashCode() != t.hashCode()); - - //Add data in same order to t - t.addValue(new double[] { 2d, 1d }); - t.addValue(new double[] { 1d, 1d }); - t.addValue(new double[] { 3d, 1d }); - t.addValue(new double[] { 4d, 1d }); - t.addValue(new double[] { 5d, 1d }); - Assert.assertTrue(t.equals(u)); - Assert.assertTrue(u.equals(t)); - Assert.assertEquals(u.hashCode(), t.hashCode()); - - // Clear and make sure summaries are indistinguishable from empty summary - u.clear(); - t.clear(); - Assert.assertTrue(t.equals(u)); - Assert.assertTrue(u.equals(t)); - Assert.assertEquals(emptyHash, t.hashCode()); - Assert.assertEquals(emptyHash, u.hashCode()); - } } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/ResizableDoubleArrayTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/ResizableDoubleArrayTest.java index dcba907a2d..51151b4127 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/ResizableDoubleArrayTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/ResizableDoubleArrayTest.java @@ -124,8 +124,7 @@ public void testConstructors() { testDa.addElement(2.0); testDa.addElement(3.2); ResizableDoubleArray copyDa = new ResizableDoubleArray(testDa); - Assert.assertEquals(copyDa, testDa); - Assert.assertEquals(testDa, copyDa); + Assert.assertArrayEquals(testDa.getElements(), copyDa.getElements(), 0); // JIRA: MATH-1252 final double[] values = {1}; @@ -446,78 +445,6 @@ public void testSubstitute() { Assert.assertEquals( "Number of elements should be 1", 1, da.getNumElements()); } - @Test - public void testEqualsAndHashCode() throws Exception { - - // Wrong type - ResizableDoubleArray first = new ResizableDoubleArray(); - Double other = Double.valueOf(2); - Assert.assertFalse(first.equals(other)); - - // Null - other = null; - Assert.assertFalse(first.equals(other)); - - // Reflexive - Assert.assertEquals(first, first); - - // Non-argument constructor - ResizableDoubleArray second = new ResizableDoubleArray(); - verifyEquality(first, second); - - // Equals iff same data, same properties - ResizableDoubleArray third = new ResizableDoubleArray(3, 2.0, 2.0); - verifyInequality(third, first); - ResizableDoubleArray fourth = new ResizableDoubleArray(3, 2.0, 2.0); - ResizableDoubleArray fifth = new ResizableDoubleArray(2, 2.0, 2.0); - verifyEquality(third, fourth); - verifyInequality(third, fifth); - third.addElement(4.1); - third.addElement(4.2); - third.addElement(4.3); - fourth.addElement(4.1); - fourth.addElement(4.2); - fourth.addElement(4.3); - verifyEquality(third, fourth); - - // expand - fourth.addElement(4.4); - verifyInequality(third, fourth); - third.addElement(4.4); - verifyEquality(third, fourth); - fourth.addElement(4.4); - verifyInequality(third, fourth); - third.addElement(4.4); - verifyEquality(third, fourth); - fourth.addElementRolling(4.5); - third.addElementRolling(4.5); - verifyEquality(third, fourth); - - // discard - third.discardFrontElements(1); - verifyInequality(third, fourth); - fourth.discardFrontElements(1); - verifyEquality(third, fourth); - - // discard recent - third.discardMostRecentElements(2); - fourth.discardMostRecentElements(2); - verifyEquality(third, fourth); - - // wrong order - third.addElement(18); - fourth.addElement(17); - third.addElement(17); - fourth.addElement(18); - verifyInequality(third, fourth); - - // Copy constructor - verifyEquality(fourth, new ResizableDoubleArray(fourth)); - - // Instance copy - verifyEquality(fourth, fourth.copy()); - } - @Test public void testGetArrayRef() { final ResizableDoubleArray a = new ResizableDoubleArray(); @@ -562,16 +489,4 @@ public double evaluate(double[] a) { final double sum = a.compute(add); Assert.assertEquals(0.5 * max * (max + 1), sum, 0); } - - private void verifyEquality(ResizableDoubleArray a, ResizableDoubleArray b) { - Assert.assertEquals(b, a); - Assert.assertEquals(a, b); - Assert.assertEquals(a.hashCode(), b.hashCode()); - } - - private void verifyInequality(ResizableDoubleArray a, ResizableDoubleArray b) { - Assert.assertNotEquals(b, a); - Assert.assertNotEquals(a, b); - Assert.assertNotEquals(a.hashCode(), b.hashCode()); - } } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticalSummaryValuesTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticalSummaryValuesTest.java index bddb0bb116..b46f77c3d7 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticalSummaryValuesTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticalSummaryValuesTest.java @@ -16,44 +16,25 @@ */ package org.apache.commons.math4.legacy.stat.descriptive; - import java.util.Locale; -import org.apache.commons.math4.legacy.TestUtils; import org.junit.Assert; import org.junit.Test; + /** * Test cases for the {@link StatisticalSummaryValues} class. - * */ - public final class StatisticalSummaryValuesTest { @Test - public void testEqualsAndHashCode() { + public void testProperties() { StatisticalSummaryValues u = new StatisticalSummaryValues(1, 2, 3, 4, 5, 6); - StatisticalSummaryValues t = null; - Assert.assertEquals("reflexive", u, u); - Assert.assertNotEquals("non-null compared to null", u, t); - Assert.assertFalse("wrong type", u.equals(Double.valueOf(0))); - t = new StatisticalSummaryValues(1, 2, 3, 4, 5, 6); - Assert.assertEquals("instances with same data should be equal", t, u); - Assert.assertEquals("hash code", u.hashCode(), t.hashCode()); - - u = new StatisticalSummaryValues(Double.NaN, 2, 3, 4, 5, 6); - t = new StatisticalSummaryValues(1, Double.NaN, 3, 4, 5, 6); - Assert.assertFalse("instances based on different data should be different", - u.equals(t) ||t.equals(u)); - } - - private void verifyEquality(StatisticalSummaryValues s, StatisticalSummaryValues u) { - Assert.assertEquals("N",s.getN(),u.getN()); - TestUtils.assertEquals("sum",s.getSum(),u.getSum(), 0); - TestUtils.assertEquals("var",s.getVariance(),u.getVariance(), 0); - TestUtils.assertEquals("std",s.getStandardDeviation(),u.getStandardDeviation(), 0); - TestUtils.assertEquals("mean",s.getMean(),u.getMean(), 0); - TestUtils.assertEquals("min",s.getMin(),u.getMin(), 0); - TestUtils.assertEquals("max",s.getMax(),u.getMax(), 0); + Assert.assertEquals(1, u.getMean(), 0); + Assert.assertEquals(2, u.getVariance(), 0); + Assert.assertEquals(3, u.getN()); + Assert.assertEquals(4, u.getMax(), 0); + Assert.assertEquals(5, u.getMin(), 0); + Assert.assertEquals(6, u.getSum(), 0); } @Test diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticsTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticsTest.java new file mode 100644 index 0000000000..012951118b --- /dev/null +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StatisticsTest.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive; + +import org.apache.commons.math4.legacy.exception.NullArgumentException; +import org.apache.commons.math4.legacy.exception.OutOfRangeException; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.Percentile; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.StorelessSumOfSquares; +import org.apache.commons.math4.legacy.stat.descriptive.Statistics.SumOfSquares; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * Test cases for the {@link Statistics} class. + */ +public class StatisticsTest { + @Test + public void testUnsupportedMethods() { + final double[] x = {1, 2, 3}; + final SumOfSquares s = SumOfSquares.getInstance(); + Assertions.assertThrows(IllegalStateException.class, () -> s.evaluate(x)); + } + + @Test + public void testUnsupportedStorelessMethods() { + final double[] x = {1, 2, 3}; + final StorelessSumOfSquares s = StorelessSumOfSquares.create(); + Assertions.assertThrows(IllegalStateException.class, () -> s.incrementAll(x)); + Assertions.assertThrows(IllegalStateException.class, () -> s.incrementAll(x, 0, 1)); + Assertions.assertThrows(IllegalStateException.class, s::getN); + Assertions.assertThrows(IllegalStateException.class, () -> s.evaluate(x)); + Assertions.assertThrows(IllegalStateException.class, () -> s.evaluate(x, 0, 1)); + } + + @ParameterizedTest + @ValueSource(doubles = {-1, 101, Double.NaN}) + public void testInvalidPercentileThrows(double p) { + final Percentile stat = Percentile.create(50); + Assertions.assertThrows(OutOfRangeException.class, () -> stat.setQuantile(p)); + Assertions.assertThrows(OutOfRangeException.class, () -> Percentile.create(p)); + } + + @Test + public void testPercentile() { + final Percentile stat = Percentile.create(50); + Assertions.assertThrows(NullArgumentException.class, () -> stat.evaluate(null)); + Assertions.assertEquals(Double.NaN, stat.evaluate(new double[] {})); + Assertions.assertEquals(1, stat.evaluate(new double[] {1})); + Assertions.assertEquals(1.5, stat.evaluate(new double[] {1, 2})); + Assertions.assertEquals(2, stat.evaluate(new double[] {1, 2, 3})); + } +} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StorelessUnivariateStatisticAbstractTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StorelessUnivariateStatisticAbstractTest.java index 3476871f98..85159d4799 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StorelessUnivariateStatisticAbstractTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/StorelessUnivariateStatisticAbstractTest.java @@ -17,7 +17,6 @@ package org.apache.commons.math4.legacy.stat.descriptive; import org.apache.commons.math4.legacy.TestUtils; -import org.apache.commons.math4.legacy.stat.descriptive.moment.SecondMoment; import org.apache.commons.math4.core.jdkmath.JdkMath; import org.junit.Assert; import org.junit.Test; @@ -74,63 +73,6 @@ protected void checkClearValue(StorelessUnivariateStatistic statistic){ Assert.assertTrue(Double.isNaN(statistic.getResult())); } - @Test - public void testEqualsAndHashCode() { - StorelessUnivariateStatistic statistic = - (StorelessUnivariateStatistic) getUnivariateStatistic(); - StorelessUnivariateStatistic statistic2 = null; - - Assert.assertFalse("non-null, compared to null", statistic.equals(statistic2)); - Assert.assertEquals("reflexive, non-null", statistic, statistic); - - int emptyHash = statistic.hashCode(); - statistic2 = (StorelessUnivariateStatistic) getUnivariateStatistic(); - Assert.assertEquals("empty stats should be equal", statistic, statistic2); - Assert.assertEquals("empty stats should have the same hash code", - emptyHash, statistic2.hashCode()); - - statistic.increment(1d); - Assert.assertEquals("reflexive, non-empty", statistic, statistic); - Assert.assertNotEquals("non-empty, compared to empty", statistic, statistic2); - Assert.assertNotEquals("non-empty, compared to empty", statistic2, statistic); - Assert.assertTrue("non-empty stat should have different hash code from empty stat", - statistic.hashCode() != emptyHash); - - statistic2.increment(1d); - Assert.assertEquals("stats with same data should be equal", statistic, statistic2); - Assert.assertEquals("stats with same data should have the same hash code", - statistic.hashCode(), statistic2.hashCode()); - - statistic.increment(Double.POSITIVE_INFINITY); - Assert.assertNotEquals("stats with different n's should not be equal", statistic2, statistic); - Assert.assertTrue("stats with different n's should have different hash codes", - statistic.hashCode() != statistic2.hashCode()); - - statistic2.increment(Double.POSITIVE_INFINITY); - Assert.assertEquals("stats with same data should be equal", statistic, statistic2); - Assert.assertEquals("stats with same data should have the same hash code", - statistic.hashCode(), statistic2.hashCode()); - - statistic.clear(); - statistic2.clear(); - Assert.assertEquals("cleared stats should be equal", statistic, statistic2); - Assert.assertEquals("cleared stats should have thash code of empty stat", - emptyHash, statistic2.hashCode()); - Assert.assertEquals("cleared stats should have thash code of empty stat", - emptyHash, statistic.hashCode()); - } - - @Test - public void testMomentSmallSamples() { - UnivariateStatistic stat = getUnivariateStatistic(); - if (stat instanceof SecondMoment) { - SecondMoment moment = (SecondMoment) getUnivariateStatistic(); - Assert.assertTrue(Double.isNaN(moment.getResult())); - moment.increment(1d); - Assert.assertEquals(0d, moment.getResult(), 0); - } - } - /** * Make sure that evaluate(double[]) and inrementAll(double[]), * getResult() give same results. @@ -169,16 +111,16 @@ public void testCopyConsistency() { replica = master.copy(); // Check same - Assert.assertEquals(replica, master); - Assert.assertEquals(master, replica); + Assert.assertEquals(master.getResult(), replica.getResult(), 0); + Assert.assertEquals(master.getN(), replica.getN()); // Now add second part to both and check again master.incrementAll(testArray, (int) index, (int) (testArray.length - index)); replica.incrementAll(testArray, (int) index, (int) (testArray.length - index)); - Assert.assertEquals(replica, master); - Assert.assertEquals(master, replica); + Assert.assertEquals(master.getResult(), replica.getResult(), 0); + Assert.assertEquals(master.getN(), replica.getN()); } /** diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/SummaryStatisticsTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/SummaryStatisticsTest.java index d5a24402ce..9112f5febb 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/SummaryStatisticsTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/SummaryStatisticsTest.java @@ -18,14 +18,13 @@ import org.apache.commons.math4.legacy.TestUtils; +import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; import org.apache.commons.math4.legacy.exception.MathIllegalStateException; -import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; -import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; -import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum; +import org.apache.commons.math4.legacy.stat.StatUtils; import org.apache.commons.math4.core.jdkmath.JdkMath; import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; /** * Test cases for the {@link SummaryStatistics} class. */ @@ -39,7 +38,6 @@ public class SummaryStatisticsTest { private final double sumSq = 18; private final double sum = 8; private final double var = 0.666666666666666666667; - private final double popVar = 0.5; private final double std = JdkMath.sqrt(var); private final double n = 4; private final double min = 1; @@ -50,6 +48,20 @@ protected SummaryStatistics createSummaryStatistics() { return new SummaryStatistics(); } + @Test + public void testEmpty() { + final SummaryStatistics stats = createSummaryStatistics(); + + final double[] x = {}; + Assertions.assertEquals(StatUtils.sum(x), stats.getSum()); + Assertions.assertEquals(StatUtils.mean(x), stats.getMean()); + final double v = StatUtils.variance(x); + Assertions.assertEquals(JdkMath.sqrt(v), stats.getStandardDeviation()); + Assertions.assertEquals(v, stats.getVariance()); + Assertions.assertEquals(StatUtils.max(x), stats.getMax()); + Assertions.assertEquals(StatUtils.min(x), stats.getMin()); + } + /** test stats */ @Test public void testStats() { @@ -61,9 +73,7 @@ public void testStats() { u.addValue(three); Assert.assertEquals("N",n,u.getN(),tolerance); Assert.assertEquals("sum",sum,u.getSum(),tolerance); - Assert.assertEquals("sumsq",sumSq,u.getSumsq(),tolerance); Assert.assertEquals("var",var,u.getVariance(),tolerance); - Assert.assertEquals("population var",popVar,u.getPopulationVariance(),tolerance); Assert.assertEquals("std",std,u.getStandardDeviation(),tolerance); Assert.assertEquals("mean",mean,u.getMean(),tolerance); Assert.assertEquals("min",min,u.getMin(),tolerance); @@ -85,7 +95,6 @@ public void testN0andN1Conditions() { /* n=1 */ u.addValue(one); Assert.assertEquals("mean should be one (n = 1)", one, u.getMean(), 0.0); - Assert.assertEquals("geometric should be one (n = 1) instead it is " + u.getGeometricMean(), one, u.getGeometricMean(), 0.0); Assert.assertEquals("Std should be zero (n = 1)", 0.0, u.getStandardDeviation(), 0.0); Assert.assertEquals("variance should be zero (n = 1)", 0.0, u.getVariance(), 0.0); @@ -97,26 +106,15 @@ public void testN0andN1Conditions() { u.getVariance() != 0.0); } - @Test - public void testProductAndGeometricMean() { - SummaryStatistics u = createSummaryStatistics(); - u.addValue( 1.0 ); - u.addValue( 2.0 ); - u.addValue( 3.0 ); - u.addValue( 4.0 ); - - Assert.assertEquals( "Geometric mean not expected", 2.213364, - u.getGeometricMean(), 0.00001 ); - } - @Test public void testNaNContracts() { SummaryStatistics u = createSummaryStatistics(); + Assert.assertTrue("sum not NaN",Double.isNaN(u.getSum())); Assert.assertTrue("mean not NaN",Double.isNaN(u.getMean())); - Assert.assertTrue("min not NaN",Double.isNaN(u.getMin())); Assert.assertTrue("std dev not NaN",Double.isNaN(u.getStandardDeviation())); Assert.assertTrue("var not NaN",Double.isNaN(u.getVariance())); - Assert.assertTrue("geom mean not NaN",Double.isNaN(u.getGeometricMean())); + Assert.assertTrue("max not NaN",Double.isNaN(u.getMax())); + Assert.assertTrue("min not NaN",Double.isNaN(u.getMin())); u.addValue(1.0); @@ -124,16 +122,6 @@ public void testNaNContracts() { u.getMean(), Double.MIN_VALUE); Assert.assertEquals( "variance not expected", 0.0, u.getVariance(), Double.MIN_VALUE); - Assert.assertEquals( "geometric mean not expected", 1.0, - u.getGeometricMean(), Double.MIN_VALUE); - - u.addValue(-1.0); - - Assert.assertTrue("geom mean not NaN",Double.isNaN(u.getGeometricMean())); - - u.addValue(0.0); - - Assert.assertTrue("geom mean not NaN",Double.isNaN(u.getGeometricMean())); //FiXME: test all other NaN contract specs } @@ -154,48 +142,6 @@ public void testGetSummary() { verifySummary(u, summary); } - @Test - public void testEqualsAndHashCode() { - SummaryStatistics u = createSummaryStatistics(); - SummaryStatistics t = null; - int emptyHash = u.hashCode(); - Assert.assertEquals("reflexive", u, u); - Assert.assertNotEquals("non-null compared to null", u, t); - Assert.assertFalse("wrong type", u.equals(Double.valueOf(0))); - t = createSummaryStatistics(); - Assert.assertEquals("empty instances should be equal", t, u); - Assert.assertEquals("empty instances should be equal", u, t); - Assert.assertEquals("empty hash code", emptyHash, t.hashCode()); - - // Add some data to u - u.addValue(2d); - u.addValue(1d); - u.addValue(3d); - u.addValue(4d); - Assert.assertNotEquals("different n's should make instances not equal", t, u); - Assert.assertNotEquals("different n's should make instances not equal", u, t); - Assert.assertTrue("different n's should make hash codes different", - u.hashCode() != t.hashCode()); - - //Add data in same order to t - t.addValue(2d); - t.addValue(1d); - t.addValue(3d); - t.addValue(4d); - Assert.assertEquals("summaries based on same data should be equal", t, u); - Assert.assertEquals("summaries based on same data should be equal", u, t); - Assert.assertEquals("summaries based on same data should have same hash codes", - u.hashCode(), t.hashCode()); - - // Clear and make sure summaries are indistinguishable from empty summary - u.clear(); - t.clear(); - Assert.assertEquals("empty instances should be equal", t, u); - Assert.assertEquals("empty instances should be equal", u, t); - Assert.assertEquals("empty hash code", emptyHash, t.hashCode()); - Assert.assertEquals("empty hash code", emptyHash, u.hashCode()); - } - @Test public void testCopy() { SummaryStatistics u = createSummaryStatistics(); @@ -204,8 +150,7 @@ public void testCopy() { u.addValue(3d); u.addValue(4d); SummaryStatistics v = new SummaryStatistics(u); - Assert.assertEquals(u, v); - Assert.assertEquals(v, u); + assertEquals(u, v); // Make sure both behave the same with additional values added u.addValue(7d); @@ -216,14 +161,31 @@ public void testCopy() { v.addValue(9d); v.addValue(11d); v.addValue(23d); - Assert.assertEquals(u, v); - Assert.assertEquals(v, u); + assertEquals(u, v); // Check implementation pointers are preserved u.clear(); - u.setSumImpl(new Sum()); + u.setSumImpl(new SumStat()); SummaryStatistics.copy(u,v); - Assert.assertEquals(u.getSumImpl(), v.getSumImpl()); + // This copy should be functionally distinct (i.e. no shared state) but + // the implementation type should be the same. + Assert.assertNotSame(u.getSumImpl(), v.getSumImpl()); + Assert.assertEquals(u.getSumImpl().getClass(), v.getSumImpl().getClass()); + } + + private static void assertEquals(SummaryStatistics summary, SummaryStatistics summary2) { + Assert.assertArrayEquals(toArray(summary), toArray(summary2), 0); + } + + private static double[] toArray(SummaryStatistics summary) { + return new double[] { + summary.getMean(), + summary.getVariance(), + summary.getN(), + summary.getMax(), + summary.getMin(), + summary.getSum(), + }; } private void verifySummary(SummaryStatistics u, StatisticalSummary s) { @@ -239,19 +201,16 @@ private void verifySummary(SummaryStatistics u, StatisticalSummary s) { @Test public void testSetterInjection() { SummaryStatistics u = createSummaryStatistics(); - u.setMeanImpl(new Sum()); - u.setSumLogImpl(new Sum()); + u.setMeanImpl(new SumStat()); u.addValue(1); u.addValue(3); Assert.assertEquals(4, u.getMean(), 1E-14); - Assert.assertEquals(4, u.getSumOfLogs(), 1E-14); - Assert.assertEquals(JdkMath.exp(2), u.getGeometricMean(), 1E-14); u.clear(); u.addValue(1); u.addValue(2); Assert.assertEquals(3, u.getMean(), 1E-14); u.clear(); - u.setMeanImpl(new Mean()); // OK after clear + u.setMeanImpl(new SumStat()); // OK after clear } @Test @@ -260,65 +219,92 @@ public void testSetterIllegalState() { u.addValue(1); u.addValue(3); try { - u.setMeanImpl(new Sum()); + u.setMeanImpl(new SumStat()); Assert.fail("Expecting MathIllegalStateException"); } catch (MathIllegalStateException ex) { // expected } } + /** + * Test when all the default implementations are overridden. + */ @Test - public void testQuadraticMean() { - final double[] values = { 1.2, 3.4, 5.6, 7.89 }; - final SummaryStatistics stats = createSummaryStatistics(); - - final int len = values.length; - double expected = 0; - for (int i = 0; i < len; i++) { - final double v = values[i]; - expected += v * v / len; - - stats.addValue(v); - } - expected = Math.sqrt(expected); - - Assert.assertEquals(expected, stats.getQuadraticMean(), Math.ulp(expected)); + public void testSetterAll() { + final SummaryStatistics u = createSummaryStatistics(); + Assertions.assertThrows(NullPointerException.class, () -> u.setSumImpl(null)); + Assertions.assertThrows(NullPointerException.class, () -> u.setMinImpl(null)); + Assertions.assertThrows(NullPointerException.class, () -> u.setMaxImpl(null)); + Assertions.assertThrows(NullPointerException.class, () -> u.setMeanImpl(null)); + Assertions.assertThrows(NullPointerException.class, () -> u.setVarianceImpl(null)); + // Distinct implementations + u.setSumImpl(new SumStat(1)); + u.setMinImpl(new SumStat(2)); + u.setMaxImpl(new SumStat(3)); + u.setMeanImpl(new SumStat(4)); + u.setVarianceImpl(new SumStat(5)); + u.addValue(1); + Assertions.assertEquals(2, u.getSum()); + Assertions.assertEquals(3, u.getMin()); + Assertions.assertEquals(4, u.getMax()); + Assertions.assertEquals(5, u.getMean()); + Assertions.assertEquals(6, u.getVariance()); + // Test getters return the correct implementation + Assertions.assertEquals(2, u.getSumImpl().getResult()); + Assertions.assertEquals(3, u.getMinImpl().getResult()); + Assertions.assertEquals(4, u.getMaxImpl().getResult()); + Assertions.assertEquals(5, u.getMeanImpl().getResult()); + Assertions.assertEquals(6, u.getVarianceImpl().getResult()); + // Test copy + final SummaryStatistics v = u.copy(); + Assertions.assertEquals(2, v.getSum()); + Assertions.assertEquals(3, v.getMin()); + Assertions.assertEquals(4, v.getMax()); + Assertions.assertEquals(5, v.getMean()); + Assertions.assertEquals(6, v.getVariance()); + // Test the return NaN contract when empty + u.clear(); + Assertions.assertEquals(Double.NaN, u.getSum()); + Assertions.assertEquals(Double.NaN, u.getMin()); + Assertions.assertEquals(Double.NaN, u.getMax()); + Assertions.assertEquals(Double.NaN, u.getMean()); + Assertions.assertEquals(Double.NaN, u.getVariance()); + // Test refilling + u.addValue(1); + Assertions.assertEquals(1, u.getSum()); + Assertions.assertEquals(1, u.getMin()); + Assertions.assertEquals(1, u.getMax()); + Assertions.assertEquals(1, u.getMean()); + Assertions.assertEquals(1, u.getVariance()); } /** - * JIRA: MATH-691 + * JIRA: MATH-691. + * Setting the variance implementation causes the StandardDevitaion to be NaN. */ @Test public void testOverrideVarianceWithMathClass() { double[] scores = {1, 2, 3, 4}; SummaryStatistics stats = new SummaryStatistics(); - stats.setVarianceImpl(new Variance(false)); //use "population variance" + stats.setVarianceImpl(new SumStat()); for(double i : scores) { stats.addValue(i); } - Assert.assertEquals((new Variance(false)).evaluate(scores),stats.getVariance(), 0); + final double expected = new SumStat().evaluate(scores); + Assert.assertEquals(expected, stats.getVariance(), 0); + Assert.assertEquals(JdkMath.sqrt(expected), stats.getStandardDeviation(), 0); } @Test public void testOverrideMeanWithMathClass() { double[] scores = {1, 2, 3, 4}; SummaryStatistics stats = new SummaryStatistics(); - stats.setMeanImpl(new Mean()); + stats.setMeanImpl(new SumStat()); for(double i : scores) { stats.addValue(i); } - Assert.assertEquals((new Mean()).evaluate(scores),stats.getMean(), 0); - } - - @Test - public void testOverrideGeoMeanWithMathClass() { - double[] scores = {1, 2, 3, 4}; - SummaryStatistics stats = new SummaryStatistics(); - stats.setGeoMeanImpl(new GeometricMean()); - for(double i : scores) { - stats.addValue(i); - } - Assert.assertEquals((new GeometricMean()).evaluate(scores),stats.getGeometricMean(), 0); + final double expected = new SumStat().evaluate(scores); + Assert.assertEquals(expected, stats.getMean(), 0); } @Test @@ -327,16 +313,80 @@ public void testToString() { for (int i = 0; i < 5; i++) { u.addValue(i); } - final String[] labels = {"min", "max", "sum", "geometric mean", "variance", - "population variance", "second moment", "sum of squares", "standard deviation", - "sum of logs"}; - final double[] values = {u.getMin(), u.getMax(), u.getSum(), u.getGeometricMean(), - u.getVariance(), u.getPopulationVariance(), u.getSecondMoment(), u.getSumsq(), - u.getStandardDeviation(), u.getSumOfLogs()}; + final String[] labels = {"min", "max", "sum", "variance", "standard deviation"}; + final double[] values = {u.getMin(), u.getMax(), u.getSum(), + u.getVariance(), u.getStandardDeviation()}; final String toString = u.toString(); Assert.assertTrue(toString.indexOf("n: " + u.getN()) > 0); // getN() returns a long for (int i = 0; i < values.length; i++) { Assert.assertTrue(toString.indexOf(labels[i] + ": " + String.valueOf(values[i])) > 0); } } + + private static final class SumStat implements StorelessUnivariateStatistic { + private double s = 0; + + /** Create an instance. */ + SumStat() {} + + /** + * Create an instance. + * + * @param sum the sum + */ + SumStat(double sum) { + s = sum; + } + + @Override + public double evaluate(double[] values) throws MathIllegalArgumentException { + double s = 0; + for (final double x : values) { + s += x; + } + return s; + } + + @Override + public double evaluate(double[] values, int begin, int length) throws MathIllegalArgumentException { + throw new IllegalStateException(); + } + + @Override + public void increment(double d) { + s += d; + } + + @Override + public void incrementAll(double[] values) throws MathIllegalArgumentException { + throw new IllegalStateException(); + } + + @Override + public void incrementAll(double[] values, int start, int length) throws MathIllegalArgumentException { + throw new IllegalStateException(); + } + + @Override + public double getResult() { + return s; + } + + @Override + public long getN() { + throw new IllegalStateException(); + } + + @Override + public void clear() { + s = 0; + } + + @Override + public StorelessUnivariateStatistic copy() { + final SumStat r = new SumStat(); + r.s = s; + return r; + } + } } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/WeightedEvaluationAbstractTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/WeightedEvaluationAbstractTest.java new file mode 100644 index 0000000000..3ef6855a43 --- /dev/null +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/WeightedEvaluationAbstractTest.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.math4.legacy.TestUtils; +import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; +import org.apache.commons.statistics.distribution.DiscreteDistribution; +import org.apache.commons.statistics.distribution.NormalDistribution; +import org.apache.commons.statistics.distribution.ContinuousDistribution; +import org.apache.commons.statistics.distribution.UniformDiscreteDistribution; +import org.apache.commons.math4.core.jdkmath.JdkMath; +import org.apache.commons.rng.simple.RandomSource; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Test cases for the {@link WeightedEvaluation} implementations. + * Based on the {@link UnivariateStatisticAbstractTest}. + */ +public abstract class WeightedEvaluationAbstractTest { + + protected double mean = 12.404545454545455d; + + protected double variance = 10.00235930735931d; + protected double std = JdkMath.sqrt(variance); + + protected double product = 628096400563833396009676.9200400128d; + protected double sum = 272.90d; + + protected double weightedMean = 12.366995073891626d; + protected double weightedVariance = 9.974760968886391d; + protected double weightedStd = JdkMath.sqrt(weightedVariance); + protected double weightedProduct = 8517647448765288000000d; + protected double weightedSum = 251.05d; + + protected double tolerance = 10E-12; + + protected double[] testArray = + { 12.5, 12.0, 11.8, 14.2, 14.9, 14.5, 21.0, 8.2, 10.3, 11.3, + 14.1, 9.9, 12.2, 12.0, 12.1, 11.0, 19.8, 11.0, 10.0, 8.8, + 9.0, 12.3 }; + + protected double[] testWeightsArray = + { 1.5, 0.8, 1.2, 0.4, 0.8, 1.8, 1.2, 1.1, 1.0, 0.7, + 1.3, 0.6, 0.7, 1.3, 0.7, 1.0, 0.4, 0.1, 1.4, 0.9, + 1.1, 0.3 }; + + protected double[] unitWeightsArray = + { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0 }; + + public abstract WeightedEvaluation getWeightedEvaluation(); + + public abstract double expectedValue(); + + public abstract double expectedUnweightedValue(); + + public double emptyValue() { + return Double.NaN; + } + + public double getTolerance() { + return tolerance; + } + + @Test + void testInvalidDataThrows() { + final WeightedEvaluation stat = getWeightedEvaluation(); + final double[] values = {1, 2, 3}; + final double[] weights = {4, 5, 6}; + Assertions.assertThrows(NullPointerException.class, () -> stat.evaluate(null, weights)); + Assertions.assertThrows(NullPointerException.class, () -> stat.evaluate(values, null)); + + final double[] w1 = Arrays.copyOf(weights, weights.length - 1); + Assertions.assertThrows(MathIllegalArgumentException.class, () -> stat.evaluate(values, w1)); + final double[] w2 = {4, Double.POSITIVE_INFINITY, 6}; + Assertions.assertThrows(MathIllegalArgumentException.class, () -> stat.evaluate(values, w2)); + final double[] w3 = {4, Double.NaN, 6}; + Assertions.assertThrows(MathIllegalArgumentException.class, () -> stat.evaluate(values, w3)); + final double[] w4 = {4, -2, 6}; + Assertions.assertThrows(MathIllegalArgumentException.class, () -> stat.evaluate(values, w4)); + + Assertions.assertThrows(MathIllegalArgumentException.class, () -> stat.evaluate(values, weights, -1, 3)); + Assertions.assertThrows(MathIllegalArgumentException.class, () -> stat.evaluate(values, weights, 1, 10)); + } + + @Test + public void testEvaluation() { + Assertions.assertEquals(expectedValue(), + getWeightedEvaluation().evaluate(testArray, testWeightsArray), getTolerance()); + } + + @Test + public void testUnweightedEvaluation() { + Assertions.assertEquals(expectedUnweightedValue(), + getWeightedEvaluation().evaluate(testArray, unitWeightsArray), getTolerance()); + } + + @Test + public void testEmptyEvaluation() { + final double[] x = {}; + Assertions.assertEquals(emptyValue(), getWeightedEvaluation().evaluate(x, x)); + Assertions.assertEquals(emptyValue(), getWeightedEvaluation().evaluate(testArray, testWeightsArray, 1, 0)); + } + + @Test + public void testEvaluateArraySegment() { + final WeightedEvaluation stat = getWeightedEvaluation(); + final double[] arrayZero = new double[5]; + System.arraycopy(testArray, 0, arrayZero, 0, 5); + double[] w = unitWeights(arrayZero.length); + Assertions.assertEquals(stat.evaluate(arrayZero, w), stat.evaluate(testArray, unitWeightsArray, 0, 5)); + final double[] arrayOne = new double[5]; + System.arraycopy(testArray, 5, arrayOne, 0, 5); + Assertions.assertEquals(stat.evaluate(arrayOne, w), stat.evaluate(testArray, unitWeightsArray, 5, 5)); + final double[] arrayEnd = new double[5]; + System.arraycopy(testArray, testArray.length - 5, arrayEnd, 0, 5); + Assertions.assertEquals(stat.evaluate(arrayEnd, w), stat.evaluate(testArray, unitWeightsArray, testArray.length - 5, 5)); + } + + @Test + public void testEvaluateArraySegmentWeighted() { + final WeightedEvaluation stat = getWeightedEvaluation(); + final double[] arrayZero = new double[5]; + final double[] weightZero = new double[5]; + System.arraycopy(testArray, 0, arrayZero, 0, 5); + System.arraycopy(testWeightsArray, 0, weightZero, 0, 5); + Assertions.assertEquals(stat.evaluate(arrayZero, weightZero), + stat.evaluate(testArray, testWeightsArray, 0, 5)); + final double[] arrayOne = new double[5]; + final double[] weightOne = new double[5]; + System.arraycopy(testArray, 5, arrayOne, 0, 5); + System.arraycopy(testWeightsArray, 5, weightOne, 0, 5); + Assertions.assertEquals(stat.evaluate(arrayOne, weightOne), + stat.evaluate(testArray, testWeightsArray, 5, 5)); + final double[] arrayEnd = new double[5]; + final double[] weightEnd = new double[5]; + System.arraycopy(testArray, testArray.length - 5, arrayEnd, 0, 5); + System.arraycopy(testWeightsArray, testArray.length - 5, weightEnd, 0, 5); + Assertions.assertEquals(stat.evaluate(arrayEnd, weightEnd), + stat.evaluate(testArray, testWeightsArray, testArray.length - 5, 5)); + } + + /** + * Tests consistency of weighted statistic computation. + * For statistics that support weighted evaluation, this test case compares + * the result of direct computation on an array with repeated values with + * a weighted computation on the corresponding (shorter) array with each + * value appearing only once but with a weight value equal to its multiplicity + * in the repeating array. + */ + @Test + public void testWeightedConsistency() { + + // See if this statistic computes weighted statistics + // If not, skip this test + final WeightedEvaluation stat = getWeightedEvaluation(); + + // Create arrays of values and corresponding integral weights + // and longer array with values repeated according to the weights + final int len = 10; // length of values array + final double mu = 0; // mean of test data + final double sigma = 5; // std dev of test data + double[] values = new double[len]; + double[] weights = new double[len]; + + // Fill weights array with random int values between 1 and 5 + int[] intWeights = new int[len]; + final DiscreteDistribution.Sampler weightDist = + UniformDiscreteDistribution.of(1, 5).createSampler(RandomSource.WELL_512_A.create(234878544L)); + for (int i = 0; i < len; i++) { + intWeights[i] = weightDist.sample(); + weights[i] = intWeights[i]; + } + + // Fill values array with random data from N(mu, sigma) + // and fill valuesList with values from values array with + // values[i] repeated weights[i] times, each i + final ContinuousDistribution.Sampler valueDist = + NormalDistribution.of(mu, sigma).createSampler(RandomSource.WELL_512_A.create(64925784252L)); + List valuesList = new ArrayList<>(); + for (int i = 0; i < len; i++) { + double value = valueDist.sample(); + values[i] = value; + for (int j = 0; j < intWeights[i]; j++) { + valuesList.add(Double.valueOf(value)); + } + } + + // Dump valuesList into repeatedValues array + int sumWeights = valuesList.size(); + double[] repeatedValues = new double[sumWeights]; + for (int i = 0; i < sumWeights; i++) { + repeatedValues[i] = valuesList.get(i); + } + + // Compare result of weighted statistic computation with direct computation + // on array of repeated values + TestUtils.assertRelativelyEquals(stat.evaluate(repeatedValues, unitWeights(repeatedValues.length)), + stat.evaluate(values, weights, 0, values.length), + 10E-12); + + // Check consistency of weighted evaluation methods + Assertions.assertEquals(stat.evaluate(values, weights, 0, values.length), + stat.evaluate(values, weights), Double.MIN_VALUE); + } + + static double[] unitWeights(int n) { + final double[] w = new double[n]; + Arrays.fill(w, 1); + return w; + } +} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FirstMomentTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FirstMomentTest.java deleted file mode 100644 index 2af8887f0b..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/FirstMomentTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cases for the {@link FirstMoment} class. - */ -public class FirstMomentTest extends StorelessUnivariateStatisticAbstractTest{ - - /** descriptive statistic. */ - protected FirstMoment stat; - - /** - * @see org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatisticAbstractTest#getUnivariateStatistic() - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new FirstMoment(); - } - - /** - * @see org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatisticAbstractTest#expectedValue() - */ - @Override - public double expectedValue() { - return this.mean; - } - - /** - * Added in an attempt to resolve MATH-1146 - * Commented out tests that won't pass with the current implementation. - */ - @Test - public void testSpecialValues() { - final FirstMoment mean = new FirstMoment(); - -// mean.clear(); -// mean.increment(Double.POSITIVE_INFINITY); -// mean.increment(1d); -// Assert.assertEquals(Double.POSITIVE_INFINITY, mean.getResult(), 0d); - -// mean.clear(); -// mean.increment(Double.POSITIVE_INFINITY); -// mean.increment(-1d); -// Assert.assertEquals(Double.POSITIVE_INFINITY, mean.getResult(), 0d); - -// mean.clear(); -// mean.increment(Double.NEGATIVE_INFINITY); -// mean.increment(1d); -// Assert.assertEquals(Double.NEGATIVE_INFINITY, mean.getResult(), 0d); - -// mean.clear(); -// mean.increment(Double.NEGATIVE_INFINITY); -// mean.increment(-1d); -// Assert.assertEquals(Double.NEGATIVE_INFINITY, mean.getResult(), 0d); - -// mean.clear(); -// mean.increment(Double.POSITIVE_INFINITY); -// mean.increment(Double.POSITIVE_INFINITY); -// Assert.assertEquals(Double.POSITIVE_INFINITY, mean.getResult(), 0d); - -// mean.clear(); -// mean.increment(Double.NEGATIVE_INFINITY); -// mean.increment(Double.NEGATIVE_INFINITY); -// Assert.assertEquals(Double.NEGATIVE_INFINITY, mean.getResult(), 0d); - - mean.clear(); - mean.increment(Double.POSITIVE_INFINITY); - mean.increment(Double.NEGATIVE_INFINITY); - Assert.assertTrue(Double.isNaN(mean.getResult())); - - mean.clear(); - mean.increment(Double.NEGATIVE_INFINITY); - mean.increment(Double.POSITIVE_INFINITY); - Assert.assertTrue(Double.isNaN(mean.getResult())); - - mean.clear(); - mean.increment(Double.NaN); - mean.increment(Double.POSITIVE_INFINITY); - Assert.assertTrue(Double.isNaN(mean.getResult())); - - mean.clear(); - mean.increment(Double.NaN); - mean.increment(Double.NEGATIVE_INFINITY); - Assert.assertTrue(Double.isNaN(mean.getResult())); - - mean.clear(); - mean.increment(Double.NaN); - mean.increment(0d); - Assert.assertTrue(Double.isNaN(mean.getResult())); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/GeometricMeanTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/GeometricMeanTest.java deleted file mode 100644 index e2604b5be1..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/GeometricMeanTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - */ -public class GeometricMeanTest extends StorelessUnivariateStatisticAbstractTest{ - - protected GeometricMean stat; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new GeometricMean(); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.geoMean; - } - - @Test - public void testSpecialValues() { - GeometricMean mean = new GeometricMean(); - // empty - Assert.assertTrue(Double.isNaN(mean.getResult())); - - // finite data - mean.increment(1d); - Assert.assertFalse(Double.isNaN(mean.getResult())); - - // add 0 -- makes log sum blow to minus infinity, should make 0 - mean.increment(0d); - Assert.assertEquals(0d, mean.getResult(), 0); - - // add positive infinity - note the minus infinity above - mean.increment(Double.POSITIVE_INFINITY); - Assert.assertTrue(Double.isNaN(mean.getResult())); - - // clear - mean.clear(); - Assert.assertTrue(Double.isNaN(mean.getResult())); - - // positive infinity by itself - mean.increment(Double.POSITIVE_INFINITY); - Assert.assertEquals(Double.POSITIVE_INFINITY, mean.getResult(), 0); - - // negative value -- should make NaN - mean.increment(-2d); - Assert.assertTrue(Double.isNaN(mean.getResult())); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/InteractionTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/InteractionTest.java deleted file mode 100644 index 66fd2f18da..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/InteractionTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.junit.Assert; -import org.junit.Test; - - -/** - */ -public class InteractionTest { - - protected double mean = 12.40454545454550; - protected double var = 10.00235930735930; - protected double skew = 1.437423729196190; - protected double kurt = 2.377191264804700; - - protected double tolerance = 10E-12; - - protected double[] testArray = - { - 12.5, - 12, - 11.8, - 14.2, - 14.9, - 14.5, - 21, - 8.2, - 10.3, - 11.3, - 14.1, - 9.9, - 12.2, - 12, - 12.1, - 11, - 19.8, - 11, - 10, - 8.8, - 9, - 12.3 }; - - @Test - public void testInteraction() { - - FourthMoment m4 = new FourthMoment(); - Mean m = new Mean(m4); - Variance v = new Variance(m4); - Skewness s= new Skewness(m4); - Kurtosis k = new Kurtosis(m4); - - for (int i = 0; i < testArray.length; i++){ - m4.increment(testArray[i]); - } - - Assert.assertEquals(mean,m.getResult(),tolerance); - Assert.assertEquals(var,v.getResult(),tolerance); - Assert.assertEquals(skew ,s.getResult(),tolerance); - Assert.assertEquals(kurt,k.getResult(),tolerance); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/KurtosisTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/KurtosisTest.java deleted file mode 100644 index 3ba3f17156..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/KurtosisTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - */ -public class KurtosisTest extends StorelessUnivariateStatisticAbstractTest{ - - protected Kurtosis stat; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new Kurtosis(); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.kurt; - } - - /** - * Make sure Double.NaN is returned iff n < 4 - */ - @Test - public void testNaN() { - Kurtosis kurt = new Kurtosis(); - Assert.assertTrue(Double.isNaN(kurt.getResult())); - kurt.increment(1d); - Assert.assertTrue(Double.isNaN(kurt.getResult())); - kurt.increment(1d); - Assert.assertTrue(Double.isNaN(kurt.getResult())); - kurt.increment(1d); - Assert.assertTrue(Double.isNaN(kurt.getResult())); - kurt.increment(1d); - Assert.assertFalse(Double.isNaN(kurt.getResult())); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/MeanTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/MeanTest.java deleted file mode 100644 index 33cada1898..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/MeanTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - */ -public class MeanTest extends StorelessUnivariateStatisticAbstractTest{ - - protected Mean stat; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new Mean(); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.mean; - } - - /**Expected value for the testArray defined in UnivariateStatisticAbstractTest */ - public double expectedWeightedValue() { - return this.weightedMean; - } - - @Test - public void testSmallSamples() { - Mean mean = new Mean(); - Assert.assertTrue(Double.isNaN(mean.getResult())); - mean.increment(1d); - Assert.assertEquals(1d, mean.getResult(), 0); - } - - @Test - public void testWeightedMean() { - Mean mean = new Mean(); - Assert.assertEquals(expectedWeightedValue(), mean.evaluate(testArray, testWeightsArray, 0, testArray.length), getTolerance()); - Assert.assertEquals(expectedValue(), mean.evaluate(testArray, identicalWeightsArray, 0, testArray.length), getTolerance()); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SemiVarianceTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SemiVarianceTest.java index 45feab4b92..320ba3a215 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SemiVarianceTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SemiVarianceTest.java @@ -20,6 +20,7 @@ import org.apache.commons.math4.legacy.TestUtils; import org.apache.commons.math4.legacy.exception.NullArgumentException; import org.apache.commons.math4.legacy.stat.StatUtils; +import org.apache.commons.math4.legacy.stat.descriptive.moment.SemiVariance.Direction; import org.junit.Assert; import org.junit.Test; @@ -37,8 +38,7 @@ public void testInsufficientData() { } try { - sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE); - sv.evaluate(nothing); + sv.evaluate(nothing, 44.0); Assert.fail("null is not a valid data array."); } catch (NullArgumentException nae) { } @@ -46,6 +46,31 @@ public void testInsufficientData() { Assert.assertTrue(Double.isNaN(sv.evaluate(nothing))); } + @Test + public void testProperties() { + SemiVariance sv = new SemiVariance(); + Assert.assertEquals(Direction.DOWNSIDE, sv.getVarianceDirection()); + sv.setVarianceDirection(Direction.UPSIDE); + Assert.assertEquals(Direction.UPSIDE, sv.getVarianceDirection()); + Assert.assertTrue(sv.isBiasCorrected()); + sv.setBiasCorrected(false); + Assert.assertFalse(sv.isBiasCorrected()); + } + + @Test + public void testCopy() { + for (Direction d : Direction.values()) { + for (boolean b : new boolean[] {true, false}) { + SemiVariance sv = new SemiVariance(); + sv.setVarianceDirection(d); + sv.setBiasCorrected(b); + SemiVariance copy = sv.copy(); + Assert.assertEquals(d, copy.getVarianceDirection()); + Assert.assertEquals(b, copy.isBiasCorrected()); + } + } + } + @Test public void testSingleDown() { SemiVariance sv = new SemiVariance(); @@ -56,7 +81,9 @@ public void testSingleDown() { @Test public void testSingleUp() { - SemiVariance sv = new SemiVariance(SemiVariance.UPSIDE_VARIANCE); + SemiVariance sv = new SemiVariance(); + sv.setVarianceDirection(Direction.UPSIDE); + Assert.assertEquals(Direction.UPSIDE, sv.getVarianceDirection()); double[] values = { 50.0d }; double singletest = sv.evaluate(values); Assert.assertEquals(0.0d, singletest, 0); @@ -69,27 +96,32 @@ public void testSample() { final double mean = StatUtils.mean(values); // 6.333... final SemiVariance sv = new SemiVariance(); // Default bias correction is true final double downsideSemiVariance = sv.evaluate(values); // Downside is the default - Assert.assertEquals(TestUtils.sumSquareDev(new double[] {-2d, 2d, 4d, -2d, 3d, 5d}, mean) / (length - 1), - downsideSemiVariance, 1E-14); + final double expectedDownside = TestUtils.sumSquareDev(new double[] {-2d, 2d, 4d, -2d, 3d, 5d}, mean) / (length - 1); + Assert.assertEquals(expectedDownside, downsideSemiVariance, 1E-14); - sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE); + sv.setVarianceDirection(Direction.UPSIDE); final double upsideSemiVariance = sv.evaluate(values); - Assert.assertEquals(TestUtils.sumSquareDev(new double[] {22d, 11d, 14d}, mean) / (length - 1), - upsideSemiVariance, 1E-14); - - // Verify that upper + lower semivariance against the mean sum to variance - Assert.assertEquals(StatUtils.variance(values), downsideSemiVariance + upsideSemiVariance, 10e-12); + final double expectedUpside = TestUtils.sumSquareDev(new double[] {22d, 11d, 14d}, mean) / (length - 1); + Assert.assertEquals(expectedUpside, upsideSemiVariance, 1E-14); + + // Test sub-range + final double[] values2 = new double[values.length + 2]; + System.arraycopy(values, 0, values2, 1, values.length); + Assert.assertEquals(expectedUpside, sv.evaluate(values2, 1, values.length), 1E-14); + sv.setVarianceDirection(Direction.DOWNSIDE); + Assert.assertEquals(expectedDownside, sv.evaluate(values2, 1, values.length), 1E-14); } @Test public void testPopulation() { double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d }; - SemiVariance sv = new SemiVariance(false); + SemiVariance sv = new SemiVariance(); + sv.setBiasCorrected(false); double singletest = sv.evaluate(values); Assert.assertEquals(19.556d, singletest, 0.01d); - sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE); + sv.setVarianceDirection(Direction.UPSIDE); singletest = sv.evaluate(values); Assert.assertEquals(36.222d, singletest, 0.01d); } @@ -97,15 +129,25 @@ public void testPopulation() { @Test public void testNonMeanCutoffs() { double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d }; - SemiVariance sv = new SemiVariance(false); // Turn off bias correction - use df = length - - double singletest = sv.evaluate(values, 1.0d, SemiVariance.DOWNSIDE_VARIANCE, false, 0, values.length); - Assert.assertEquals(TestUtils.sumSquareDev(new double[] { -2d, -2d }, 1.0d) / values.length, - singletest, 0.01d); - - singletest = sv.evaluate(values, 3.0d, SemiVariance.UPSIDE_VARIANCE, false, 0, values.length); - Assert.assertEquals(TestUtils.sumSquareDev(new double[] { 4d, 22d, 11d, 14d, 5d }, 3.0d) / values.length, singletest, - 0.01d); + SemiVariance sv = new SemiVariance(); + // Turn off bias correction - use df = length + sv.setBiasCorrected(false); + + double singletest = sv.evaluate(values, 1.0d, 0, values.length); + final double expectedDownside = TestUtils.sumSquareDev(new double[] { -2d, -2d }, 1.0d) / values.length; + Assert.assertEquals(expectedDownside, singletest, 0.01d); + + sv.setVarianceDirection(Direction.UPSIDE); + singletest = sv.evaluate(values, 3.0d, 0, values.length); + final double expectedUpside = TestUtils.sumSquareDev(new double[] { 4d, 22d, 11d, 14d, 5d }, 3.0d) / values.length; + Assert.assertEquals(expectedUpside, singletest, 0.01d); + + // Test sub-range + final double[] values2 = new double[values.length + 2]; + System.arraycopy(values, 0, values2, 1, values.length); + Assert.assertEquals(expectedUpside, sv.evaluate(values2, 3.0d, 1, values.length), 1E-14); + sv.setVarianceDirection(Direction.DOWNSIDE); + Assert.assertEquals(expectedDownside, sv.evaluate(values2, 1.0d, 1, values.length), 1E-14); } /** @@ -116,10 +158,10 @@ public void testNonMeanCutoffs() { public void testVarianceDecompMeanCutoff() { double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d }; double variance = StatUtils.variance(values); - SemiVariance sv = new SemiVariance(true); // Bias corrected - sv.setVarianceDirection(SemiVariance.DOWNSIDE_VARIANCE); + SemiVariance sv = new SemiVariance(); + sv.setVarianceDirection(Direction.DOWNSIDE); final double lower = sv.evaluate(values); - sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE); + sv.setVarianceDirection(Direction.UPSIDE); final double upper = sv.evaluate(values); Assert.assertEquals(variance, lower + upper, 10e-12); } @@ -134,10 +176,10 @@ public void testVarianceDecompNonMeanCutoff() { double[] values = { -2.0d, 2.0d, 4.0d, -2.0d, 22.0d, 11.0d, 3.0d, 14.0d, 5.0d }; double target = 0; double totalSumOfSquares = TestUtils.sumSquareDev(values, target); - SemiVariance sv = new SemiVariance(true); // Bias corrected - sv.setVarianceDirection(SemiVariance.DOWNSIDE_VARIANCE); + SemiVariance sv = new SemiVariance(); + sv.setVarianceDirection(Direction.DOWNSIDE); double lower = sv.evaluate(values, target); - sv.setVarianceDirection(SemiVariance.UPSIDE_VARIANCE); + sv.setVarianceDirection(Direction.UPSIDE); double upper = sv.evaluate(values, target); Assert.assertEquals(totalSumOfSquares / (values.length - 1), lower + upper, 10e-12); } @@ -147,7 +189,8 @@ public void testNoVariance() { final double[] values = {100d, 100d, 100d, 100d}; SemiVariance sv = new SemiVariance(); Assert.assertEquals(0, sv.evaluate(values), 10E-12); + Assert.assertEquals(0, sv.evaluate(values, 1, 2), 10E-12); Assert.assertEquals(0, sv.evaluate(values, 100d), 10E-12); - Assert.assertEquals(0, sv.evaluate(values, 100d, SemiVariance.UPSIDE_VARIANCE, false, 0, values.length), 10E-12); + Assert.assertEquals(0, sv.evaluate(values, 100d, 1, 2), 10E-12); } } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SkewnessTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SkewnessTest.java deleted file mode 100644 index aa0124f2a9..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/SkewnessTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - * - */ -public class SkewnessTest extends StorelessUnivariateStatisticAbstractTest{ - - protected Skewness stat; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new Skewness(); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.skew; - } - - /** - * Make sure Double.NaN is returned iff n < 3 - */ - @Test - public void testNaN() { - Skewness skew = new Skewness(); - Assert.assertTrue(Double.isNaN(skew.getResult())); - skew.increment(1d); - Assert.assertTrue(Double.isNaN(skew.getResult())); - skew.increment(1d); - Assert.assertTrue(Double.isNaN(skew.getResult())); - skew.increment(1d); - Assert.assertFalse(Double.isNaN(skew.getResult())); - } - - @Test - public void testZeroSkewness() { - final double[] values = {2, 2, 2, 2}; - Assert.assertEquals(0, new Skewness().evaluate(values), 0.0); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/StandardDeviationTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/StandardDeviationTest.java deleted file mode 100644 index 2063e5d2fa..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/StandardDeviationTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.apache.commons.math4.core.jdkmath.JdkMath; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - * - */ -public class StandardDeviationTest extends StorelessUnivariateStatisticAbstractTest{ - - protected StandardDeviation stat; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new StandardDeviation(); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.std; - } - - /** - * Make sure Double.NaN is returned iff n = 0 - * - */ - @Test - public void testNaN() { - StandardDeviation std = new StandardDeviation(); - Assert.assertTrue(Double.isNaN(std.getResult())); - std.increment(1d); - Assert.assertEquals(0d, std.getResult(), 0); - } - - /** - * Test population version of variance - */ - @Test - public void testPopulation() { - double[] values = {-1.0d, 3.1d, 4.0d, -2.1d, 22d, 11.7d, 3d, 14d}; - double sigma = populationStandardDeviation(values); - SecondMoment m = new SecondMoment(); - m.incrementAll(values); // side effect is to add values - StandardDeviation s1 = new StandardDeviation(); - s1.setBiasCorrected(false); - Assert.assertEquals(sigma, s1.evaluate(values), 1E-14); - s1.incrementAll(values); - Assert.assertEquals(sigma, s1.getResult(), 1E-14); - s1 = new StandardDeviation(false, m); - Assert.assertEquals(sigma, s1.getResult(), 1E-14); - s1 = new StandardDeviation(false); - Assert.assertEquals(sigma, s1.evaluate(values), 1E-14); - s1.incrementAll(values); - Assert.assertEquals(sigma, s1.getResult(), 1E-14); - } - - /** - * Definitional formula for population standard deviation - */ - protected double populationStandardDeviation(double[] v) { - double mean = new Mean().evaluate(v); - double sum = 0; - for (int i = 0; i < v.length; i++) { - sum += (v[i] - mean) * (v[i] - mean); - } - return JdkMath.sqrt(sum / v.length); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VarianceTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VarianceTest.java deleted file mode 100644 index 37675d2bc1..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/VarianceTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.apache.commons.math4.legacy.core.MathArrays; -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.junit.Assert; -import org.junit.Test; -import org.junit.jupiter.api.Assertions; - -/** - * Test cases for the {@link UnivariateStatistic} class. - * - */ -public class VarianceTest extends StorelessUnivariateStatisticAbstractTest{ - - protected Variance stat; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new Variance(); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.var; - } - - /**Expected value for the testArray defined in UnivariateStatisticAbstractTest */ - public double expectedWeightedValue() { - return this.weightedVar; - } - - /** - * Make sure Double.NaN is returned iff n = 0 - * - */ - @Test - public void testNaN() { - StandardDeviation std = new StandardDeviation(); - Assert.assertTrue(Double.isNaN(std.getResult())); - std.increment(1d); - Assert.assertEquals(0d, std.getResult(), 0); - } - - /** - * Test population version of variance - */ - @Test - public void testPopulation() { - double[] values = {-1.0d, 3.1d, 4.0d, -2.1d, 22d, 11.7d, 3d, 14d}; - SecondMoment m = new SecondMoment(); - m.incrementAll(values); // side effect is to add values - Variance v1 = new Variance(); - v1.setBiasCorrected(false); - Assert.assertEquals(populationVariance(values), v1.evaluate(values), 1E-14); - v1.incrementAll(values); - Assert.assertEquals(populationVariance(values), v1.getResult(), 1E-14); - v1 = new Variance(false, m); - Assert.assertEquals(populationVariance(values), v1.getResult(), 1E-14); - v1 = new Variance(false); - Assert.assertEquals(populationVariance(values), v1.evaluate(values), 1E-14); - v1.incrementAll(values); - Assert.assertEquals(populationVariance(values), v1.getResult(), 1E-14); - } - - /** - * Definitional formula for population variance - */ - protected double populationVariance(double[] v) { - double mean = new Mean().evaluate(v); - double sum = 0; - for (int i = 0; i < v.length; i++) { - sum += (v[i] - mean) * (v[i] - mean); - } - return sum / v.length; - } - - @Test - public void testWeightedVariance() { - Variance variance = new Variance(); - Assert.assertEquals(expectedWeightedValue(), - variance.evaluate(testArray, testWeightsArray, 0, testArray.length), getTolerance()); - - // All weights = 1 -> weighted variance = unweighted variance - Assert.assertEquals(expectedValue(), - variance.evaluate(testArray, unitWeightsArray, 0, testArray.length), getTolerance()); - - // All weights the same -> when weights are normalized to sum to the length of the values array, - // weighted variance = unweighted value - Assert.assertEquals(expectedValue(), - variance.evaluate(testArray, MathArrays.normalizeArray(identicalWeightsArray, testArray.length), - 0, testArray.length), getTolerance()); - } - - @Test - public void testZeroWeights() { - Variance variance = new Variance(); - final double[] values = {1, 2, 3, 4}; - final double[] weights = new double[values.length]; - - // No weights - Assertions.assertThrows(MathIllegalArgumentException.class, () -> { - variance.evaluate(values, weights); - }); - - // No length - final int begin = 1; - final int zeroLength = 0; - Assertions.assertEquals(Double.NaN, variance.evaluate(values, weights, begin, zeroLength)); - - // One weight (must be non-zero) - Assertions.assertThrows(MathIllegalArgumentException.class, () -> { - variance.evaluate(values, weights, begin, zeroLength + 1); - }); - - weights[begin] = Double.MIN_VALUE; - Assertions.assertEquals(0.0, variance.evaluate(values, weights, begin, zeroLength + 1)); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/ThirdMomentTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedMeanTest.java similarity index 56% rename from commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/ThirdMomentTest.java rename to commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedMeanTest.java index d04fe61a73..c227c92d39 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/ThirdMomentTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedMeanTest.java @@ -16,30 +16,26 @@ */ package org.apache.commons.math4.legacy.stat.descriptive.moment; -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; +import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation; +import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluationAbstractTest; /** - * Test cases for the {@link ThirdMoment} class. + * Test cases for the {@link WeightedMean} class. */ -public class ThirdMomentTest extends StorelessUnivariateStatisticAbstractTest{ +public class WeightedMeanTest extends WeightedEvaluationAbstractTest { - /** descriptive statistic. */ - protected ThirdMoment stat; - - /** - * @see org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatisticAbstractTest#getUnivariateStatistic() - */ @Override - public UnivariateStatistic getUnivariateStatistic() { - return new ThirdMoment(); + public WeightedEvaluation getWeightedEvaluation() { + return WeightedMean.getInstance(); } - /** - * @see org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatisticAbstractTest#expectedValue() - */ @Override public double expectedValue() { - return this.thirdMoment; + return weightedMean; + } + + @Override + public double expectedUnweightedValue() { + return mean; } } diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedVarianceTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedVarianceTest.java new file mode 100644 index 0000000000..168bc6bae2 --- /dev/null +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/moment/WeightedVarianceTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.moment; + +import java.util.Arrays; +import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluation; +import org.apache.commons.math4.legacy.stat.descriptive.WeightedEvaluationAbstractTest; +import org.apache.commons.statistics.descriptive.Mean; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Test cases for the {@link WeightedVariance} class. + */ +public class WeightedVarianceTest extends WeightedEvaluationAbstractTest { + + @Override + public WeightedEvaluation getWeightedEvaluation() { + return WeightedVariance.getInstance(); + } + + @Override + public double expectedValue() { + return weightedVariance; + } + + @Override + public double expectedUnweightedValue() { + return variance; + } + + /** + * Test population version of variance + */ + @Test + public void testPopulation() { + final double[] values = {-1.0d, 3.1d, 4.0d, -2.1d, 22d, 11.7d, 3d, 14d}; + final double[] weights = new double[values.length]; + Arrays.fill(weights, 1); + final WeightedVariance v1 = WeightedVariance.getInstance(); + v1.setBiasCorrected(false); + Assertions.assertEquals(populationVariance(values), v1.evaluate(values, weights), 1E-14); + } + + /** + * Definitional formula for population variance + */ + protected double populationVariance(double[] v) { + final double mean = Mean.of(v).getAsDouble(); + double sum = 0; + for (int i = 0; i < v.length; i++) { + sum += (v[i] - mean) * (v[i] - mean); + } + return sum / v.length; + } +} + diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/KthSelectorTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/KthSelectorTest.java deleted file mode 100644 index c99798adea..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/KthSelectorTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import static org.junit.Assert.assertEquals; - -import java.util.Arrays; -import java.util.Random; - -import org.junit.Test; - -public class KthSelectorTest { - - @Test - public void testRandom() { - - final int numIterations = 100000; - final double[] possibleValues = {Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.MAX_VALUE, Double.MIN_VALUE, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, -0., 0., 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - final Random rnd = new Random(0); - for (int i = 0; i < numIterations; ++i) { - - final int dataSize = rnd.nextInt(30); - - final double[] data = new double[dataSize]; - - for (int j = 0; j < dataSize; ++j) { - data[j] = possibleValues[rnd.nextInt(possibleValues.length)]; - } - - final double[] dataSorted = Arrays.copyOf(data, data.length); - Arrays.sort(dataSorted); - - for (int j = 0; j < dataSize; ++j) { - - final double[] dataTmp = Arrays.copyOf(data, data.length); - final double resultKthSelector = new KthSelector().select(dataTmp, null, j); - final double resultSort = dataSorted[j]; - assertEquals(Double.doubleToLongBits(resultKthSelector), Double.doubleToLongBits(resultSort)); - } - } - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MaxTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MaxTest.java deleted file mode 100644 index 3311eb8da3..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MaxTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - */ -public class MaxTest extends StorelessUnivariateStatisticAbstractTest { - - protected Max stat; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new Max(); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.max; - } - - @Test - public void testSpecialValues() { - double[] testArray = {0d, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}; - Max max = new Max(); - Assert.assertTrue(Double.isNaN(max.getResult())); - max.increment(testArray[0]); - Assert.assertEquals(0d, max.getResult(), 0); - max.increment(testArray[1]); - Assert.assertEquals(0d, max.getResult(), 0); - max.increment(testArray[2]); - Assert.assertEquals(0d, max.getResult(), 0); - max.increment(testArray[3]); - Assert.assertEquals(Double.POSITIVE_INFINITY, max.getResult(), 0); - Assert.assertEquals(Double.POSITIVE_INFINITY, max.evaluate(testArray), 0); - } - - @Test - public void testNaNs() { - Max max = new Max(); - double nan = Double.NaN; - Assert.assertEquals(3d, max.evaluate(new double[]{nan, 2d, 3d}), 0); - Assert.assertEquals(3d, max.evaluate(new double[]{1d, nan, 3d}), 0); - Assert.assertEquals(2d, max.evaluate(new double[]{1d, 2d, nan}), 0); - Assert.assertTrue(Double.isNaN(max.evaluate(new double[]{nan, nan, nan}))); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MedianTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MedianTest.java deleted file mode 100644 index d963d971d8..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MedianTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.LEGACY; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_1; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_2; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_3; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_4; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_5; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_6; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_7; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_8; -import static org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType.R_9; - -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType; -import org.apache.commons.statistics.ranking.NaNStrategy; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - */ -public class MedianTest extends UnivariateStatisticAbstractTest{ - - protected Median stat; - - /** - * {@link org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType type} - * to be used while calling - * {@link #getUnivariateStatistic()} - */ - protected EstimationType estimationType = LEGACY; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new Median(); - } - - private Median getTestMedian(EstimationType type) { - NaNStrategy strategy = (type == LEGACY) ? NaNStrategy.FIXED : NaNStrategy.REMOVED; - return new Median().withEstimationType(type).withNaNStrategy(strategy); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.median; - } - - @Before - public void before() { - estimationType=LEGACY; - } - - @Test - public void testAllTechniquesSingleton() { - double[] singletonArray = new double[] { 1d }; - for (EstimationType e : EstimationType.values()) { - UnivariateStatistic percentile = getTestMedian(e); - Assert.assertEquals(1d, percentile.evaluate(singletonArray), 0); - Assert.assertEquals(1d, percentile.evaluate(singletonArray, 0, 1), 0); - Assert.assertEquals(1d, new Median().evaluate(singletonArray, 0, 1, 5), 0); - Assert.assertEquals(1d, new Median().evaluate(singletonArray, 0, 1, 100), 0); - Assert.assertTrue(Double.isNaN(percentile.evaluate(singletonArray, 0, 0))); - } - } - - @Test - public void testAllTechniquesMedian() { - double[] d = new double[] { 1, 3, 2, 4 }; - testAssertMappedValues(d, new Object[][] { { LEGACY, 2.5d }, - { R_1, 2d }, { R_2, 2.5d }, { R_3, 2d }, { R_4, 2d }, { R_5, 2.5 }, - { R_6, 2.5 },{ R_7, 2.5 },{ R_8, 2.5 }, { R_9 , 2.5 } }, 1.0e-05); - } - - /** - * Simple test assertion utility method - * - * @param d input data - * @param map of expected result against a {@link EstimationType} - * @param tolerance the tolerance of difference allowed - */ - protected void testAssertMappedValues(double[] d, Object[][] map, Double tolerance) { - for (Object[] o : map) { - EstimationType e = (EstimationType) o[0]; - double expected = (Double) o[1]; - double result = getTestMedian(e).evaluate(d); - Assert.assertEquals("expected[" + e + "] = " + expected + - " but was = " + result, expected, result, tolerance); - } - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MinTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MinTest.java deleted file mode 100644 index 0f6ce3b721..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/MinTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import org.apache.commons.math4.legacy.stat.descriptive.StorelessUnivariateStatisticAbstractTest; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.junit.Assert; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - */ -public class MinTest extends StorelessUnivariateStatisticAbstractTest{ - - protected Min stat; - - /** - * {@inheritDoc} - */ - @Override - public UnivariateStatistic getUnivariateStatistic() { - return new Min(); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.min; - } - - @Test - public void testSpecialValues() { - double[] testArray = {0d, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY}; - Min min = new Min(); - Assert.assertTrue(Double.isNaN(min.getResult())); - min.increment(testArray[0]); - Assert.assertEquals(0d, min.getResult(), 0); - min.increment(testArray[1]); - Assert.assertEquals(0d, min.getResult(), 0); - min.increment(testArray[2]); - Assert.assertEquals(0d, min.getResult(), 0); - min.increment(testArray[3]); - Assert.assertEquals(Double.NEGATIVE_INFINITY, min.getResult(), 0); - Assert.assertEquals(Double.NEGATIVE_INFINITY, min.evaluate(testArray), 0); - } - - @Test - public void testNaNs() { - Min min = new Min(); - double nan = Double.NaN; - Assert.assertEquals(2d, min.evaluate(new double[]{nan, 2d, 3d}), 0); - Assert.assertEquals(1d, min.evaluate(new double[]{1d, nan, 3d}), 0); - Assert.assertEquals(1d, min.evaluate(new double[]{1d, 2d, nan}), 0); - Assert.assertTrue(Double.isNaN(min.evaluate(new double[]{nan, nan, nan}))); - } -} diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PSquarePercentileTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PSquarePercentileTest.java index cd2687fbb0..c671de6c08 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PSquarePercentileTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PSquarePercentileTest.java @@ -19,12 +19,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; import org.apache.commons.statistics.distribution.LogNormalDistribution; import org.apache.commons.statistics.distribution.NormalDistribution; +import org.apache.commons.statistics.descriptive.Quantile; +import org.apache.commons.statistics.descriptive.Quantile.EstimationMethod; import org.apache.commons.statistics.distribution.ContinuousDistribution; import org.apache.commons.math4.legacy.distribution.AbstractRealDistribution; import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; @@ -81,16 +79,14 @@ public void testCopyConsistencyWithInitialMostElements() { replica = master.copy(); // Check same - Assert.assertEquals(replica, master); - Assert.assertEquals(master, replica); + Assert.assertEquals(master.getResult(), replica.getResult(), 0); // Now add second part to both and check again master.incrementAll(testArray, (int) index, (int) (testArray.length - index)); replica.incrementAll(testArray, (int) index, (int) (testArray.length - index)); - Assert.assertEquals(replica, master); - Assert.assertEquals(master, replica); + Assert.assertEquals(master.getResult(), replica.getResult(), 0); } /** @@ -115,19 +111,14 @@ public void testCopyConsistencyWithInitialFirstFewElements() { replica = master.copy(); // Check same - Assert.assertEquals(replica, master); - Assert.assertEquals(master, replica); + Assert.assertEquals(master.getResult(), replica.getResult(), 0); // Now add second part to both and check again master.incrementAll(testArray, (int) index, (int) (testArray.length - index)); replica.incrementAll(testArray, (int) index, (int) (testArray.length - index)); // Check same - // Explicit test of the equals method - Assert.assertTrue(master.equals(master)); - Assert.assertTrue(replica.equals(replica)); - Assert.assertEquals(replica, master); - Assert.assertEquals(master, replica); + Assert.assertEquals(master.getResult(), replica.getResult(), 0); } @Test(expected = MathIllegalArgumentException.class) @@ -138,37 +129,6 @@ public void testNullListInMarkers() { PSquarePercentile.newMarkers(null, 0); } - @Test - public void testEqualsInMarkers() { - double p = 0.5; - PSquareMarkers markers = - PSquarePercentile.newMarkers( - Arrays.asList(new Double[] { 0.02, 1.18, 9.15, 21.91, - 38.62 }), p); - // Markers equality - Assert.assertEquals(markers, markers); - Assert.assertNotEquals(markers, null); - Assert.assertNotEquals(markers, ""); - // Check for null markers test during equality testing - // Until 5 elements markers are not initialized - PSquarePercentile p1 = new PSquarePercentile(); - PSquarePercentile p2 = new PSquarePercentile(); - Assert.assertEquals(p1, p2); - p1.evaluate(new double[] { 1.0, 2.0, 3.0 }); - p2.evaluate(new double[] { 1.0, 2.0, 3.0 }); - Assert.assertEquals(p1, p2); - // Move p2 alone with more values just to make sure markers are not null - // for p2 - p2.incrementAll(new double[] { 5.0, 7.0, 11.0 }); - Assert.assertNotEquals(p1, p2); - Assert.assertNotEquals(p2, p1); - // Next add different data to p1 to make number of elements match and - // markers are not null however actual results will vary - p1.incrementAll(new double[] { 20, 21, 22, 23 }); - Assert.assertNotEquals(p1, p2);// though markers are non null, N - // matches, results wont - } - @Test(expected = OutOfRangeException.class) public void testMarkersOORLow() { PSquarePercentile.newMarkers( @@ -183,92 +143,6 @@ public void testMarkersOORHigh() { 0.5).estimate(5); } - @Test - public void testMarkers2() { - double p = 0.5; - PSquareMarkers markers = - PSquarePercentile.newMarkers( - Arrays.asList(new Double[] { 0.02, 1.18, 9.15, 21.91, - 38.62 }), p); - - PSquareMarkers markersNew = - PSquarePercentile.newMarkers( - Arrays.asList(new Double[] { 0.02, 1.18, 9.15, 21.91, - 38.62 }), p); - - Assert.assertEquals(markers, markersNew); - // If just one element of markers got changed then its still false. - markersNew.processDataPoint(39); - Assert.assertNotEquals(markers, markersNew); - } - - @Test - public void testHashCodeInMarkers() { - PSquarePercentile p = new PSquarePercentile(95); - PSquarePercentile p2 = new PSquarePercentile(95); - Set s = new HashSet<>(); - s.add(p); - s.add(p2); - Assert.assertEquals(1, s.size()); - Assert.assertEquals(p, s.iterator().next()); - double[] d = - new double[] { 95.1772, 95.1567, 95.1937, 95.1959, 95.1442, - 95.0610, 95.1591, 95.1195, 95.1772, 95.0925, 95.1990, - 95.1682 }; - Assert.assertEquals(95.1981, p.evaluate(d), 1.0e-2); // change - Assert.assertEquals(95.1981, p2.evaluate(d), 1.0e-2); // change - s.clear(); - s.add(p); - s.add(p2); - Assert.assertEquals(1, s.size()); - Assert.assertEquals(p, s.iterator().next()); - - PSquareMarkers m1 = - PSquarePercentile.newMarkers( - Arrays.asList(new Double[] { 95.1772, 95.1567, 95.1937, - 95.1959, 95.1442, 95.0610, 95.1591, 95.1195, - 95.1772, 95.0925, 95.1990, 95.1682 }), 0.0); - PSquareMarkers m2 = - PSquarePercentile.newMarkers( - Arrays.asList(new Double[] { 95.1772, 95.1567, 95.1937, - 95.1959, 95.1442, 95.0610, 95.1591, 95.1195, - 95.1772, 95.0925, 95.1990, 95.1682 }), 0.0); - Assert.assertEquals(m1, m2); - Set setMarkers = new LinkedHashSet<>(); - Assert.assertTrue(setMarkers.add(m1)); - Assert.assertFalse(setMarkers.add(m2)); - Assert.assertEquals(1, setMarkers.size()); - - PSquareMarkers mThis = - PSquarePercentile.newMarkers( - Arrays.asList(new Double[] { 195.1772, 195.1567, - 195.1937, 195.1959, 95.1442, 195.0610, - 195.1591, 195.1195, 195.1772, 95.0925, 95.1990, - 195.1682 }), 0.50); - PSquareMarkers mThat = - PSquarePercentile.newMarkers( - Arrays.asList(new Double[] { 95.1772, 95.1567, 95.1937, - 95.1959, 95.1442, 95.0610, 95.1591, 95.1195, - 95.1772, 95.0925, 95.1990, 95.1682 }), 0.50); - Assert.assertEquals(mThis, mThis); - Assert.assertNotEquals(mThis, mThat); - String s1=""; - Assert.assertNotEquals(mThis, s1); - for (int i = 0; i < testArray.length; i++) { - mThat.processDataPoint(testArray[i]); - } - setMarkers.add(mThat); - setMarkers.add(mThis); - Assert.assertEquals(mThat, mThat); - Assert.assertTrue(setMarkers.contains(mThat)); - Assert.assertTrue(setMarkers.contains(mThis)); - Assert.assertEquals(3, setMarkers.size()); - Iterator iterator=setMarkers.iterator(); - Assert.assertEquals(m1, iterator.next()); - Assert.assertEquals(mThat, iterator.next()); - Assert.assertEquals(mThis, iterator.next()); - } - @Test(expected = OutOfRangeException.class) public void testMarkersWithLowerIndex() { PSquareMarkers mThat = @@ -546,45 +420,50 @@ private void assertValues(Double a, Double b, double delta) { } } - private void doCalculatePercentile(Double percentile, Number[] test) { - doCalculatePercentile(percentile, test, Double.MAX_VALUE); + private void doCalculatePercentile(Double percentile, Number[] test, boolean copy) { + // TODO: Correct this delta so the test does more than simply checking + // the result is either NaN or finite. + doCalculatePercentile(percentile, test, Double.MAX_VALUE, copy); } private void doCalculatePercentile(Double percentile, Number[] test, - double delta) { + double delta, boolean copy) { PSquarePercentile psquared = new PSquarePercentile(percentile); for (Number value : test) { psquared.increment(value.doubleValue()); } - Percentile p2 = new Percentile(percentile * 100); - double[] dall = new double[test.length]; for (int i = 0; i < test.length; i++) { dall[i] = test[i].doubleValue(); } - Double referenceValue = p2.evaluate(dall); + double referenceValue = computePercentile(dall, percentile, copy); assertValues(psquared.getResult(), referenceValue, delta); } private void doCalculatePercentile(double percentile, double[] test, - double delta) { + double delta, boolean copy) { PSquarePercentile psquared = new PSquarePercentile(percentile); for (double value : test) { psquared.increment(value); } - Percentile p2 = - new Percentile(percentile < 1 ? percentile * 100 : percentile); /* * double[] dall = new double[test.length]; for (int i = 0; i < * test.length; i++) dall[i] = test[i]; */ - Double referenceValue = p2.evaluate(test); + double referenceValue = computePercentile(test, percentile, copy); assertValues(psquared.getResult(), referenceValue, delta); } + private double computePercentile(double[] test, double percentile, boolean copy) { + return Quantile.withDefaults() + .with(EstimationMethod.HF6) + .withCopy(copy) + .evaluate(test, percentile / 100); + } + @Test public void testCannedDataSet() { // test.unoverride("dump"); @@ -599,56 +478,56 @@ public void testCannedDataSet() { input[i] = seedInput[i % seedInput.length] + i; } // Arrays.sort(input); - doCalculatePercentile(0.50d, input); - doCalculatePercentile(0.95d, input); + doCalculatePercentile(50d, input, true); + doCalculatePercentile(95d, input, false); } @Test public void test99Percentile() { Double[] test = randomTestData(100, 10000); - doCalculatePercentile(0.99d, test); + doCalculatePercentile(99d, test, false); } @Test public void test90Percentile() { Double[] test = randomTestData(100, 10000); - doCalculatePercentile(0.90d, test); + doCalculatePercentile(90d, test, false); } @Test public void test20Percentile() { Double[] test = randomTestData(100, 100000); - doCalculatePercentile(0.20d, test); + doCalculatePercentile(20d, test, false); } @Test public void test5Percentile() { Double[] test = randomTestData(50, 990000); - doCalculatePercentile(0.50d, test); + doCalculatePercentile(50d, test, false); } @Test public void test99PercentileHighValues() { Double[] test = randomTestData(100000, 10000); - doCalculatePercentile(0.99d, test); + doCalculatePercentile(99d, test, false); } @Test public void test90PercentileHighValues() { Double[] test = randomTestData(100000, 100000); - doCalculatePercentile(0.90d, test); + doCalculatePercentile(90d, test, false); } @Test public void test20PercentileHighValues() { Double[] test = randomTestData(100000, 100000); - doCalculatePercentile(0.20d, test); + doCalculatePercentile(20d, test, false); } @Test public void test5PercentileHighValues() { Double[] test = randomTestData(100000, 100000); - doCalculatePercentile(0.05d, test); + doCalculatePercentile(5d, test, false); } @Test @@ -711,40 +590,40 @@ private void doDistributionTest(ContinuousDistribution distribution) { double data[]; data = AbstractRealDistribution.sample(VERY_LARGE, sampler); - doCalculatePercentile(50, data, 0.0001); - doCalculatePercentile(95, data, 0.0001); + doCalculatePercentile(50, data, 0.0001, true); + doCalculatePercentile(95, data, 0.0001, false); data = AbstractRealDistribution.sample(LARGE, sampler); - doCalculatePercentile(50, data, 0.001); - doCalculatePercentile(95, data, 0.001); + doCalculatePercentile(50, data, 0.001, true); + doCalculatePercentile(95, data, 0.001, false); data = AbstractRealDistribution.sample(VERY_BIG, sampler); - doCalculatePercentile(50, data, 0.001); - doCalculatePercentile(95, data, 0.001); + doCalculatePercentile(50, data, 0.001, true); + doCalculatePercentile(95, data, 0.001, false); data = AbstractRealDistribution.sample(BIG, sampler); - doCalculatePercentile(50, data, 0.001); - doCalculatePercentile(95, data, 0.001); + doCalculatePercentile(50, data, 0.001, true); + doCalculatePercentile(95, data, 0.001, false); data = AbstractRealDistribution.sample(STANDARD, sampler); - doCalculatePercentile(50, data, 0.005); - doCalculatePercentile(95, data, 0.005); + doCalculatePercentile(50, data, 0.005, true); + doCalculatePercentile(95, data, 0.005, false); data = AbstractRealDistribution.sample(MEDIUM, sampler); - doCalculatePercentile(50, data, 0.005); - doCalculatePercentile(95, data, 0.005); + doCalculatePercentile(50, data, 0.005, true); + doCalculatePercentile(95, data, 0.005, false); data = AbstractRealDistribution.sample(NOMINAL, sampler); - doCalculatePercentile(50, data, 0.01); - doCalculatePercentile(95, data, 0.01); + doCalculatePercentile(50, data, 0.01, true); + doCalculatePercentile(95, data, 0.01, false); data = AbstractRealDistribution.sample(SMALL, sampler); - doCalculatePercentile(50, data, 0.01); - doCalculatePercentile(95, data, 0.01); + doCalculatePercentile(50, data, 0.01, true); + doCalculatePercentile(95, data, 0.01, false); data = AbstractRealDistribution.sample(TINY, sampler); - doCalculatePercentile(50, data, 0.05); - doCalculatePercentile(95, data, 0.05); + doCalculatePercentile(50, data, 0.05, true); + doCalculatePercentile(95, data, 0.05, false); } /** diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PercentileTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PercentileTest.java deleted file mode 100644 index d09d7d2823..0000000000 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/stat/descriptive/rank/PercentileTest.java +++ /dev/null @@ -1,1044 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.apache.commons.math4.legacy.stat.descriptive.rank; - -import java.util.Arrays; - -import org.apache.commons.statistics.distribution.ContinuousDistribution; -import org.apache.commons.math4.legacy.distribution.AbstractRealDistribution; -import org.apache.commons.statistics.distribution.NormalDistribution; -import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; -import org.apache.commons.math4.legacy.exception.NotANumberException; -import org.apache.commons.math4.legacy.exception.NotPositiveException; -import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; -import org.apache.commons.math4.legacy.exception.NullArgumentException; -import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException; -import org.apache.commons.math4.legacy.exception.OutOfRangeException; -import org.apache.commons.rng.simple.RandomSource; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic; -import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatisticAbstractTest; -import org.apache.commons.statistics.ranking.NaNStrategy; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * Test cases for the {@link UnivariateStatistic} class. - */ -public class PercentileTest extends UnivariateStatisticAbstractTest{ - - protected Percentile stat; - - private double quantile; - - /** - * {@link org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile.EstimationType type} - * of estimation to be used while calling {@link #getUnivariateStatistic()} - */ - private Percentile.EstimationType type; - - /** - * {@link NaNStrategy} - * of estimation to be used while calling {@link #getUnivariateStatistic()} - */ - private NaNStrategy nanStrategy; - - /** - * kth selector - */ - private KthSelector kthSelector; - - /** - * A default percentile to be used for {@link #getUnivariateStatistic()} - */ - protected final double DEFAULT_PERCENTILE = 95d; - - /** - * Before method to ensure defaults retained - */ - @Before - public void before() { - quantile = 95.0; - type = Percentile.EstimationType.LEGACY; - nanStrategy = NaNStrategy.REMOVED; - kthSelector = new KthSelector(new MedianOf3PivotingStrategy()); - } - - private void reset(final double p, final Percentile.EstimationType type) { - this.quantile = p; - this.type = type; - nanStrategy = (type == Percentile.EstimationType.LEGACY) ? NaNStrategy.FIXED : NaNStrategy.REMOVED; - } - - /** - * {@inheritDoc} - */ - @Override - public Percentile getUnivariateStatistic() { - return new Percentile(quantile). - withEstimationType(type). - withNaNStrategy(nanStrategy). - withKthSelector(kthSelector); - } - - /** - * {@inheritDoc} - */ - @Override - public double expectedValue() { - return this.percentile95; - } - - @Test - public void testHighPercentile(){ - final double[] d = new double[]{1, 2, 3}; - final Percentile p = new Percentile(75); - Assert.assertEquals(3.0, p.evaluate(d), 1.0e-5); - } - - @Test - public void testLowPercentile() { - final double[] d = new double[] {0, 1}; - final Percentile p = new Percentile(25); - Assert.assertEquals(0d, p.evaluate(d), Double.MIN_VALUE); - } - - @Test - public void testPercentile() { - final double[] d = new double[] {1, 3, 2, 4}; - final Percentile p = new Percentile(30); - Assert.assertEquals(1.5, p.evaluate(d), 1.0e-5); - p.setQuantile(25); - Assert.assertEquals(1.25, p.evaluate(d), 1.0e-5); - p.setQuantile(75); - Assert.assertEquals(3.75, p.evaluate(d), 1.0e-5); - p.setQuantile(50); - Assert.assertEquals(2.5, p.evaluate(d), 1.0e-5); - - // invalid percentiles - try { - p.evaluate(d, 0, d.length, -1.0); - Assert.fail(); - } catch (final MathIllegalArgumentException ex) { - // success - } - try { - p.evaluate(d, 0, d.length, 101.0); - Assert.fail(); - } catch (final MathIllegalArgumentException ex) { - // success - } - } - - @Test - public void testNISTExample() { - final double[] d = new double[] {95.1772, 95.1567, 95.1937, 95.1959, - 95.1442, 95.0610, 95.1591, 95.1195, 95.1772, 95.0925, 95.1990, 95.1682 - }; - final Percentile p = new Percentile(90); - Assert.assertEquals(95.1981, p.evaluate(d), 1.0e-4); - Assert.assertEquals(95.1990, p.evaluate(d,0,d.length, 100d), 0); - } - - @Test - public void test5() { - final Percentile percentile = new Percentile(5); - Assert.assertEquals(this.percentile5, percentile.evaluate(testArray), getTolerance()); - } - - @Test - public void testNullEmpty() { - final Percentile percentile = new Percentile(50); - final double[] nullArray = null; - final double[] emptyArray = new double[] {}; - try { - percentile.evaluate(nullArray); - Assert.fail("Expecting NullArgumentException for null array"); - } catch (final NullArgumentException ex) { - // expected - } - Assert.assertTrue(Double.isNaN(percentile.evaluate(emptyArray))); - } - - @Test - public void testSingleton() { - final Percentile percentile = new Percentile(50); - final double[] singletonArray = new double[] {1d}; - Assert.assertEquals(1d, percentile.evaluate(singletonArray), 0); - Assert.assertEquals(1d, percentile.evaluate(singletonArray, 0, 1), 0); - Assert.assertEquals(1d, percentile.evaluate(singletonArray, 0, 1, 5), 0); - Assert.assertEquals(1d, percentile.evaluate(singletonArray, 0, 1, 100), 0); - Assert.assertTrue(Double.isNaN(percentile.evaluate(singletonArray, 0, 0))); - } - - @Test - public void testSpecialValues() { - final Percentile percentile = new Percentile(50); - double[] specialValues = new double[] {0d, 1d, 2d, 3d, 4d, Double.NaN}; - Assert.assertEquals(/*2.5d*/2d, percentile.evaluate(specialValues), 0); - specialValues = new double[] {Double.NEGATIVE_INFINITY, 1d, 2d, 3d, - Double.NaN, Double.POSITIVE_INFINITY}; - Assert.assertEquals(/*2.5d*/2d, percentile.evaluate(specialValues), 0); - specialValues = new double[] {1d, 1d, Double.POSITIVE_INFINITY, - Double.POSITIVE_INFINITY}; - Assert.assertTrue(Double.isInfinite(percentile.evaluate(specialValues))); - specialValues = new double[] {1d, 1d, Double.NaN, - Double.NaN}; - Assert.assertFalse(Double.isNaN(percentile.evaluate(specialValues))); - Assert.assertEquals(1d, percentile.evaluate(specialValues), 0.0); - specialValues = new double[] {1d, 1d, Double.NEGATIVE_INFINITY, - Double.NEGATIVE_INFINITY}; - // Interpolation results in NEGATIVE_INFINITY + POSITIVE_INFINITY - Assert.assertTrue(Double.isNaN(percentile.evaluate(specialValues))); - } - - @Test - public void testSetQuantile() { - final Percentile percentile = new Percentile(10); - percentile.setQuantile(100); // OK - Assert.assertEquals(100, percentile.getQuantile(), 0); - try { - percentile.setQuantile(0); - Assert.fail("Expecting MathIllegalArgumentException"); - } catch (final MathIllegalArgumentException ex) { - // expected - } - try { - new Percentile(0); - Assert.fail("Expecting MathIllegalArgumentException"); - } catch (final MathIllegalArgumentException ex) { - // expected - } - } - - //Below tests are basically to run for all estimation types. - /** - * While {@link #testHighPercentile()} checks only for the existing - * implementation; this method verifies for all the types including Percentile.Type.CM Percentile.Type. - */ - @Test - public void testAllTechniquesHighPercentile() { - final double[] d = new double[] { 1, 2, 3 }; - testAssertMappedValues(d, new Object[][] { { Percentile.EstimationType.LEGACY, 3d }, { Percentile.EstimationType.R_1, 3d }, - { Percentile.EstimationType.R_2, 3d }, { Percentile.EstimationType.R_3, 2d }, { Percentile.EstimationType.R_4, 2.25 }, { Percentile.EstimationType.R_5, 2.75 }, - { Percentile.EstimationType.R_6, 3d }, { Percentile.EstimationType.R_7, 2.5 },{ Percentile.EstimationType.R_8, 2.83333 }, {Percentile.EstimationType.R_9,2.81250} }, - 75d, 1.0e-5); - } - - @Test - public void testAllTechniquesLowPercentile() { - final double[] d = new double[] { 0, 1 }; - testAssertMappedValues(d, new Object[][] { { Percentile.EstimationType.LEGACY, 0d }, { Percentile.EstimationType.R_1, 0d }, - { Percentile.EstimationType.R_2, 0d }, { Percentile.EstimationType.R_3, 0d }, { Percentile.EstimationType.R_4, 0d }, {Percentile.EstimationType.R_5, 0d}, {Percentile.EstimationType.R_6, 0d}, - { Percentile.EstimationType.R_7, 0.25 }, { Percentile.EstimationType.R_8, 0d }, {Percentile.EstimationType.R_9, 0d} }, - 25d, Double.MIN_VALUE); - } - - public void checkAllTechniquesPercentile() { - final double[] d = new double[] { 1, 3, 2, 4 }; - - testAssertMappedValues(d, new Object[][] { { Percentile.EstimationType.LEGACY, 1.5d }, - { Percentile.EstimationType.R_1, 2d }, { Percentile.EstimationType.R_2, 2d }, { Percentile.EstimationType.R_3, 1d }, { Percentile.EstimationType.R_4, 1.2 }, {Percentile.EstimationType.R_5, 1.7}, - { Percentile.EstimationType.R_6, 1.5 },{ Percentile.EstimationType.R_7, 1.9 }, { Percentile.EstimationType.R_8, 1.63333 },{ Percentile.EstimationType.R_9, 1.65 } }, - 30d, 1.0e-05); - - testAssertMappedValues(d, new Object[][] { { Percentile.EstimationType.LEGACY, 1.25d }, - { Percentile.EstimationType.R_1, 1d }, { Percentile.EstimationType.R_2, 1.5d }, { Percentile.EstimationType.R_3, 1d }, { Percentile.EstimationType.R_4, 1d }, {Percentile.EstimationType.R_5, 1.5}, - { Percentile.EstimationType.R_6, 1.25 },{ Percentile.EstimationType.R_7, 1.75 }, - { Percentile.EstimationType.R_8, 1.41667 }, { Percentile.EstimationType.R_9, 1.43750 } }, 25d, 1.0e-05); - - testAssertMappedValues(d, new Object[][] { { Percentile.EstimationType.LEGACY, 3.75d }, - { Percentile.EstimationType.R_1, 3d }, { Percentile.EstimationType.R_2, 3.5d }, { Percentile.EstimationType.R_3, 3d }, { Percentile.EstimationType.R_4, 3d }, - { Percentile.EstimationType.R_5, 3.5d },{ Percentile.EstimationType.R_6, 3.75d }, { Percentile.EstimationType.R_7, 3.25 }, - { Percentile.EstimationType.R_8, 3.58333 },{ Percentile.EstimationType.R_9, 3.56250} }, 75d, 1.0e-05); - - testAssertMappedValues(d, new Object[][] { { Percentile.EstimationType.LEGACY, 2.5d }, - { Percentile.EstimationType.R_1, 2d }, { Percentile.EstimationType.R_2, 2.5d }, { Percentile.EstimationType.R_3, 2d }, { Percentile.EstimationType.R_4, 2d }, - { Percentile.EstimationType.R_5, 2.5 },{ Percentile.EstimationType.R_6, 2.5 },{ Percentile.EstimationType.R_7, 2.5 }, - { Percentile.EstimationType.R_8, 2.5 },{ Percentile.EstimationType.R_9, 2.5 } }, 50d, 1.0e-05); - - // invalid percentiles - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - try { - reset(-1.0, e); - getUnivariateStatistic().evaluate(d, 0, d.length); - Assert.fail(); - } catch (final MathIllegalArgumentException ex) { - // success - } - } - - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - try { - reset(101.0, e); - getUnivariateStatistic().evaluate(d, 0, d.length); - Assert.fail(); - } catch (final MathIllegalArgumentException ex) { - // success - } - } - } - - @Test - public void testAllTechniquesPercentileUsingMedianOf3Pivoting() { - kthSelector = new KthSelector(new MedianOf3PivotingStrategy()); - Assert.assertEquals(MedianOf3PivotingStrategy.class, - getUnivariateStatistic().getPivotingStrategy().getClass()); - checkAllTechniquesPercentile(); - } - - @Test - public void testAllTechniquesPercentileUsingCentralPivoting() { - kthSelector = new KthSelector(new CentralPivotingStrategy()); - Assert.assertEquals(CentralPivotingStrategy.class, - getUnivariateStatistic().getPivotingStrategy().getClass()); - checkAllTechniquesPercentile(); - } - - @Test - public void testAllTechniquesPercentileUsingRandomPivoting() { - kthSelector = new KthSelector(new RandomPivotingStrategy(RandomSource.WELL_1024_A, 0x268a7fb4194240f6L)); - Assert.assertEquals(RandomPivotingStrategy.class, - getUnivariateStatistic().getPivotingStrategy().getClass()); - checkAllTechniquesPercentile(); - } - - @Test - public void testAllTechniquesNISTExample() { - final double[] d = - new double[] { 95.1772, 95.1567, 95.1937, 95.1959, 95.1442, - 95.0610, 95.1591, 95.1195, 95.1772, 95.0925, 95.1990, - 95.1682 }; - - testAssertMappedValues(d, new Object[][] { { Percentile.EstimationType.LEGACY, 95.1981 }, - { Percentile.EstimationType.R_1, 95.19590 }, { Percentile.EstimationType.R_2, 95.19590 }, { Percentile.EstimationType.R_3, 95.19590 }, - { Percentile.EstimationType.R_4, 95.19546 }, { Percentile.EstimationType.R_5, 95.19683 }, { Percentile.EstimationType.R_6, 95.19807 }, - { Percentile.EstimationType.R_7, 95.19568 }, { Percentile.EstimationType.R_8, 95.19724 }, { Percentile.EstimationType.R_9, 95.19714 } }, 90d, - 1.0e-04); - - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset(100.0, e); - Assert.assertEquals(95.1990, getUnivariateStatistic().evaluate(d), 1.0e-4); - } - } - - @Test - public void testAllTechniques5() { - reset(5, Percentile.EstimationType.LEGACY); - final UnivariateStatistic percentile = getUnivariateStatistic(); - Assert.assertEquals(this.percentile5, percentile.evaluate(testArray), - getTolerance()); - testAssertMappedValues(testArray, - new Object[][] { { Percentile.EstimationType.LEGACY, percentile5 }, { Percentile.EstimationType.R_1, 8.8000 }, - { Percentile.EstimationType.R_2, 8.8000 }, { Percentile.EstimationType.R_3, 8.2000 }, { Percentile.EstimationType.R_4, 8.2600 }, - { Percentile.EstimationType.R_5, 8.5600 }, { Percentile.EstimationType.R_6, 8.2900 }, - { Percentile.EstimationType.R_7, 8.8100 }, { Percentile.EstimationType.R_8, 8.4700 }, - { Percentile.EstimationType.R_9, 8.4925 }}, 5d, getTolerance()); - } - - @Test - public void testAllTechniquesNullEmpty() { - - final double[] nullArray = null; - final double[] emptyArray = new double[] {}; - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset (50, e); - final UnivariateStatistic percentile = getUnivariateStatistic(); - try { - percentile.evaluate(nullArray); - Assert.fail("Expecting NullArgumentException " - + "for null array"); - } catch (final NullArgumentException ex) { - // expected - } - Assert.assertTrue(Double.isNaN(percentile.evaluate(emptyArray))); - } - } - - @Test - public void testAllTechniquesSingleton() { - final double[] singletonArray = new double[] { 1d }; - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset (50, e); - final UnivariateStatistic percentile = getUnivariateStatistic(); - Assert.assertEquals(1d, percentile.evaluate(singletonArray), 0); - Assert.assertEquals(1d, percentile.evaluate(singletonArray, 0, 1), - 0); - Assert.assertEquals(1d, - new Percentile().evaluate(singletonArray, 0, 1, 5), 0); - Assert.assertEquals(1d, - new Percentile().evaluate(singletonArray, 0, 1, 100), 0); - Assert.assertTrue(Double.isNaN(percentile.evaluate(singletonArray, - 0, 0))); - } - } - - @Test - public void testAllTechniquesEmpty() { - final double[] singletonArray = new double[] { }; - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset (50, e); - final UnivariateStatistic percentile = getUnivariateStatistic(); - Assert.assertEquals(Double.NaN, percentile.evaluate(singletonArray), - 0); - Assert.assertEquals(Double.NaN, percentile.evaluate(singletonArray, - 0, 0), - 0); - Assert.assertEquals(Double.NaN, - new Percentile().evaluate(singletonArray, 0, 0, 5), 0); - Assert.assertEquals(Double.NaN, - new Percentile().evaluate(singletonArray, 0, 0, 100), 0); - Assert.assertTrue(Double.isNaN(percentile.evaluate(singletonArray, - 0, 0))); - } - } - - @Test - public void testReplaceNanInRange() { - final double[] specialValues = - new double[] { 0d, 1d, 2d, 3d, 4d, Double.NaN, Double.NaN, 5d, - 7d, Double.NaN, 8d}; - Assert.assertEquals(/*Double.NaN*/3.5,new Percentile(50d).evaluate(specialValues),0d); - reset (50, Percentile.EstimationType.R_1); - Assert.assertEquals(3d, getUnivariateStatistic().evaluate(specialValues),0d); - reset (50, Percentile.EstimationType.R_2); - Assert.assertEquals(3.5d, getUnivariateStatistic().evaluate(specialValues),0d); - Assert.assertEquals(Double.POSITIVE_INFINITY,new Percentile(70) - .withNaNStrategy(NaNStrategy.MAXIMAL) - .evaluate(specialValues),0d); - } - - @Test - public void testRemoveNan() { - final double[] specialValues = - new double[] { 0d, 1d, 2d, 3d, 4d, Double.NaN }; - final double[] expectedValues = - new double[] { 0d, 1d, 2d, 3d, 4d }; - reset (50, Percentile.EstimationType.R_1); - Assert.assertEquals(2.0, getUnivariateStatistic().evaluate(specialValues), 0d); - Assert.assertEquals(2.0, getUnivariateStatistic().evaluate(expectedValues),0d); - Assert.assertTrue(Double.isNaN(getUnivariateStatistic().evaluate(specialValues,5,1))); - Assert.assertEquals(4d, getUnivariateStatistic().evaluate(specialValues, 4, 2), 0d); - Assert.assertEquals(3d, getUnivariateStatistic().evaluate(specialValues,3,3),0d); - reset(50, Percentile.EstimationType.R_2); - Assert.assertEquals(3.5d, getUnivariateStatistic().evaluate(specialValues,3,3),0d); - } - - @Test - public void testPercentileCopy() { - reset(50d, Percentile.EstimationType.LEGACY); - final Percentile original = getUnivariateStatistic(); - final Percentile copy = new Percentile(original); - Assert.assertEquals(original.getNaNStrategy(),copy.getNaNStrategy()); - Assert.assertEquals(original.getQuantile(), copy.getQuantile(),0d); - Assert.assertEquals(original.getEstimationType(),copy.getEstimationType()); - Assert.assertEquals(NaNStrategy.FIXED, original.getNaNStrategy()); - } - - @Test - public void testAllTechniquesSpecialValues() { - reset(50d, Percentile.EstimationType.LEGACY); - final UnivariateStatistic percentile = getUnivariateStatistic(); - double[] specialValues = - new double[] { 0d, 1d, 2d, 3d, 4d, Double.NaN }; - Assert.assertEquals(2.5d, percentile.evaluate(specialValues), 0); - - testAssertMappedValues(specialValues, new Object[][] { - { Percentile.EstimationType.LEGACY, 2.5d }, { Percentile.EstimationType.R_1, 2.0 }, { Percentile.EstimationType.R_2, 2.0 }, { Percentile.EstimationType.R_3, 1.0 }, - { Percentile.EstimationType.R_4, 1.5 }, { Percentile.EstimationType.R_5, 2.0 }, { Percentile.EstimationType.R_6, 2.0 }, - { Percentile.EstimationType.R_7, 2.0 }, { Percentile.EstimationType.R_8, 2.0 }, { Percentile.EstimationType.R_9, 2.0 }}, 50d, 0d); - - specialValues = - new double[] { Double.NEGATIVE_INFINITY, 1d, 2d, 3d, - Double.NaN, Double.POSITIVE_INFINITY }; - Assert.assertEquals(2.5d, percentile.evaluate(specialValues), 0); - - testAssertMappedValues(specialValues, new Object[][] { - { Percentile.EstimationType.LEGACY, 2.5d }, { Percentile.EstimationType.R_1, 2.0 }, { Percentile.EstimationType.R_2, 2.0 }, { Percentile.EstimationType.R_3, 1.0 }, - { Percentile.EstimationType.R_4, 1.5 }, { Percentile.EstimationType.R_5, 2.0 }, { Percentile.EstimationType.R_7, 2.0 }, { Percentile.EstimationType.R_7, 2.0 }, - { Percentile.EstimationType.R_8, 2.0 }, { Percentile.EstimationType.R_9, 2.0 } }, 50d, 0d); - - specialValues = - new double[] { 1d, 1d, Double.POSITIVE_INFINITY, - Double.POSITIVE_INFINITY }; - Assert.assertTrue(Double.isInfinite(percentile.evaluate(specialValues))); - - testAssertMappedValues(specialValues, new Object[][] { - // This is one test not matching with R results. - { Percentile.EstimationType.LEGACY, Double.POSITIVE_INFINITY }, - { Percentile.EstimationType.R_1,/* 1.0 */Double.NaN }, - { Percentile.EstimationType.R_2, /* Double.POSITIVE_INFINITY */Double.NaN }, - { Percentile.EstimationType.R_3, /* 1.0 */Double.NaN }, { Percentile.EstimationType.R_4, /* 1.0 */Double.NaN }, - { Percentile.EstimationType.R_5, Double.POSITIVE_INFINITY }, - { Percentile.EstimationType.R_6, Double.POSITIVE_INFINITY }, - { Percentile.EstimationType.R_7, Double.POSITIVE_INFINITY }, - { Percentile.EstimationType.R_8, Double.POSITIVE_INFINITY }, - { Percentile.EstimationType.R_9, Double.POSITIVE_INFINITY }, }, 50d, 0d); - - specialValues = new double[] { 1d, 1d, Double.NaN, Double.NaN }; - Assert.assertTrue(Double.isNaN(percentile.evaluate(specialValues))); - testAssertMappedValues(specialValues, new Object[][] { - { Percentile.EstimationType.LEGACY, Double.NaN }, { Percentile.EstimationType.R_1, 1.0 }, { Percentile.EstimationType.R_2, 1.0 }, { Percentile.EstimationType.R_3, 1.0 }, - { Percentile.EstimationType.R_4, 1.0 }, { Percentile.EstimationType.R_5, 1.0 },{ Percentile.EstimationType.R_6, 1.0 },{ Percentile.EstimationType.R_7, 1.0 }, - { Percentile.EstimationType.R_8, 1.0 }, { Percentile.EstimationType.R_9, 1.0 },}, 50d, 0d); - - specialValues = - new double[] { 1d, 1d, Double.NEGATIVE_INFINITY, - Double.NEGATIVE_INFINITY }; - - testAssertMappedValues(specialValues, new Object[][] { - { Percentile.EstimationType.LEGACY, Double.NaN }, { Percentile.EstimationType.R_1, Double.NaN }, - { Percentile.EstimationType.R_2, Double.NaN }, { Percentile.EstimationType.R_3, Double.NaN }, { Percentile.EstimationType.R_4, Double.NaN }, - { Percentile.EstimationType.R_5, Double.NaN }, { Percentile.EstimationType.R_6, Double.NaN }, - { Percentile.EstimationType.R_7, Double.NaN }, { Percentile.EstimationType.R_8, Double.NaN }, { Percentile.EstimationType.R_9, Double.NaN } - }, 50d, 0d); - } - - @Test - public void testAllTechniquesSetQuantile() { - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset(10, e); - final Percentile percentile = getUnivariateStatistic(); - percentile.setQuantile(100); // OK - Assert.assertEquals(100, percentile.getQuantile(), 0); - try { - percentile.setQuantile(0); - Assert.fail("Expecting MathIllegalArgumentException"); - } catch (final MathIllegalArgumentException ex) { - // expected - } - try { - new Percentile(0); - Assert.fail("Expecting MathIllegalArgumentException"); - } catch (final MathIllegalArgumentException ex) { - // expected - } - } - } - - @Test - public void testAllTechniquesEvaluateArraySegmentWeighted() { - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset(quantile, e); - testEvaluateArraySegmentWeighted(); - } - } - - @Test - public void testAllTechniquesEvaluateArraySegment() { - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset(quantile, e); - testEvaluateArraySegment(); - } - } - - @Test - public void testAllTechniquesWeightedConsistency() { - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset(quantile, e); - testWeightedConsistency(); - } - } - - @Test - public void testAllTechniquesEvaluation() { - - testAssertMappedValues(testArray, new Object[][] { { Percentile.EstimationType.LEGACY, 20.820 }, - { Percentile.EstimationType.R_1, 19.800 }, { Percentile.EstimationType.R_2, 19.800 }, { Percentile.EstimationType.R_3, 19.800 }, - { Percentile.EstimationType.R_4, 19.310 }, { Percentile.EstimationType.R_5, 20.280 }, { Percentile.EstimationType.R_6, 20.820 }, - { Percentile.EstimationType.R_7, 19.555 }, { Percentile.EstimationType.R_8, 20.460 },{ Percentile.EstimationType.R_9, 20.415} }, - DEFAULT_PERCENTILE, tolerance); - } - - @Test - public void testPercentileWithTechnique() { - reset (50, Percentile.EstimationType.LEGACY); - final Percentile p = getUnivariateStatistic(); - Assert.assertEquals(Percentile.EstimationType.LEGACY, p.getEstimationType()); - Assert.assertNotEquals(Percentile.EstimationType.R_1, p.getEstimationType()); - } - - static final int TINY = 10; - static final int SMALL = 50; - static final int NOMINAL = 100; - static final int MEDIUM = 500; - static final int STANDARD = 1000; - static final int BIG = 10000; - static final int VERY_BIG = 50000; - static final int LARGE = 1000000; - static final int VERY_LARGE = 10000000; - static final int[] sampleSizes = {TINY , SMALL , NOMINAL , MEDIUM , - STANDARD, BIG }; - - @Test - public void testStoredVsDirect() { - final ContinuousDistribution.Sampler sampler = - NormalDistribution.of(4000, 50).createSampler(RandomSource.JDK.create(Long.MAX_VALUE)); - - for (final int sampleSize : sampleSizes) { - final double[] data = AbstractRealDistribution.sample(sampleSize, sampler); - for (final double p : new double[] { 50d, 95d }) { - for (final Percentile.EstimationType e : Percentile.EstimationType.values()) { - reset(p, e); - final Percentile pStoredData = getUnivariateStatistic(); - pStoredData.setData(data); - final double storedDataResult = pStoredData.evaluate(); - pStoredData.setData(null); - final Percentile pDirect = getUnivariateStatistic(); - Assert.assertEquals("Sample=" + sampleSize + ", P=" + p + " e=" + e, - storedDataResult, - pDirect.evaluate(data), 0d); - } - } - } - } - - @Test - public void testPercentileWithDataRef() { - reset(50.0, Percentile.EstimationType.R_7); - final Percentile p = getUnivariateStatistic(); - p.setData(testArray); - Assert.assertEquals(Percentile.EstimationType.R_7, p.getEstimationType()); - Assert.assertNotEquals(Percentile.EstimationType.R_1, p.getEstimationType()); - Assert.assertEquals(12d, p.evaluate(), 0d); - Assert.assertEquals(12.16d, p.evaluate(60d), 0d); - } - - @Test(expected=NullArgumentException.class) - public void testNullEstimation() { - type = null; - getUnivariateStatistic(); - } - - @Test - public void testAllEstimationTechniquesOnlyLimits() { - final int N=testArray.length; - - final double[] input = Arrays.copyOf(testArray, testArray.length); - Arrays.sort(input); - final double min = input[0]; - final double max=input[input.length-1]; - //limits may be ducked by 0.01 to induce the condition of p 1.5 * glsBetaStats.getMean()); + Assertions.assertTrue(olsBetaStats.getMean() > 1.1 * glsBetaStats.getMean(), + () -> String.format("OLS %s : GLS %s", olsBetaStats.getMean(), glsBetaStats.getMean())); Assert.assertTrue(olsBetaStats.getStandardDeviation() > glsBetaStats.getStandardDeviation()); } } diff --git a/pom.xml b/pom.xml index 1e6ea46d66..fced971de6 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 1.2 1.6 1.0 - 1.1 + 1.2-SNAPSHOT 3.6.1 ${basedir} diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 5cf3192ff9..4ebf514106 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -96,6 +96,10 @@ Caveat: to support the whole codebase (it was one of the main reasons for creating more focused components). "> + + Update o.a.c.m.legacy.stat.descriptive package. Functionality has been + partially transferred to Commons Statistics descriptive. + Removed o.a.c.m.legacy.stat.ranking package. Functionality has been transferred to Commons Statistics ranking. diff --git a/src/site/xdoc/userguide/stat.xml b/src/site/xdoc/userguide/stat.xml index f3efff751f..b03df0dcbd 100644 --- a/src/site/xdoc/userguide/stat.xml +++ b/src/site/xdoc/userguide/stat.xml @@ -41,21 +41,24 @@

- The stat package includes a framework and default implementations for - the following Descriptive statistics: -

    -
  • arithmetic and geometric means
  • -
  • variance and standard deviation
  • -
  • sum, product, log sum, sum of squared values
  • -
  • minimum, maximum, median, and percentiles
  • -
  • skewness and kurtosis
  • -
  • first, second, third and fourth moments
  • -
+ Univariate statistics are now available in the + + Commons Statistics component in the commons-statistics-descriptive module. + The Commons Statistics API supports Java streams for double, int + and long values and computation on corresponding data types for + arrays and array ranges. Integer type specialisations are used where possible + for increased accuracy and performance over using double values.

- With the exception of percentiles and the median, all of these - statistics can be computed without maintaining the full list of input - data values in memory. The stat package provides interfaces and + Many implementations found in previous versions of Commons Math have been removed + as their functionality is entirely superceded by Commons Statistics. + The summary statistic functionality in Commons Math now + uses Commons Statistics to compute the results. + The statistics framework is maintained to support the remaining functionality in + Commons Math described in the following sections. +

+

+ The stat package provides framework interfaces for implementations that do not require value storage as well as implementations that operate on arrays of stored values.

@@ -63,7 +66,7 @@ The top level interface is UnivariateStatistic. - This interface, implemented by all statistics, consists of + This interface consists of evaluate() methods that take double[] arrays as arguments and return the value of the statistic. This interface is extended by @@ -81,12 +84,10 @@ AbstractStorelessUnivariateStatistic respectively.

- Each statistic is implemented as a separate class, in one of the + Statistic implementations are provided as a separate class, in one of the subpackages (moment, rank, summary) and each extends one of the abstract classes above (depending on whether or not value storage is required to - compute the statistic). There are several ways to instantiate and use statistics. - Statistics can be instantiated and used directly, but it is generally more convenient - (and efficient) to access them using the provided aggregates, + compute the statistic). Computation of multiple statistics is performed by DescriptiveStatistics and @@ -112,10 +113,16 @@ sum, sum of squares, standard deviation, variance, percentiles, skewness, kurtosis, medianYesYes - SummaryStatisticsmin, max, mean, geometric mean, n, - sum, sum of squares, standard deviation, varianceNoNo + SummaryStatisticsmin, max, mean, n, + sum, standard deviation, varianceNoNo

+

+ Both DescriptiveStatistics and SummaryStatistics allow + the implementation for the statistic to be changed. This requires an instance + of either UnivariateStatistic or StorelessUnivariateStatistic + respectively. +

SummaryStatistics can be aggregated using