From d092e095316d89d297eec0917d5763e15702d7d8 Mon Sep 17 00:00:00 2001 From: Gilles Sadowski Date: Tue, 11 Oct 2011 23:37:57 +0000 Subject: [PATCH] MATH-689 Moved array utilities from "MathUtils" to "MathArrays". git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1182147 13f79535-47bb-0310-9956-ffa450edef68 --- .../stat/descriptive/moment/Variance.java | 8 +-- .../apache/commons/math/util/MathArrays.java | 56 +++++++++++++++++++ .../apache/commons/math/util/MathUtils.java | 52 ----------------- .../stat/descriptive/moment/VarianceTest.java | 4 +- .../commons/math/util/MathArraysTest.java | 48 ++++++++++++++++ .../commons/math/util/MathUtilsTest.java | 49 ---------------- 6 files changed, 110 insertions(+), 107 deletions(-) diff --git a/src/main/java/org/apache/commons/math/stat/descriptive/moment/Variance.java b/src/main/java/org/apache/commons/math/stat/descriptive/moment/Variance.java index 124d266f1..3a22cc8cf 100644 --- a/src/main/java/org/apache/commons/math/stat/descriptive/moment/Variance.java +++ b/src/main/java/org/apache/commons/math/stat/descriptive/moment/Variance.java @@ -273,7 +273,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se * weights are to be treated as "expansion values," as will be the case if for example * the weights represent frequency counts. To normalize weights so that the denominator * in the variance computation equals the length of the input vector minus one, use
-     *   evaluate(values, MathUtils.normalizeArray(weights, values.length)); 
+     *   evaluate(values, MathArrays.normalizeArray(weights, values.length)); 
      * 
*

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

@@ -332,7 +332,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se * weights are to be treated as "expansion values," as will be the case if for example * the weights represent frequency counts. To normalize weights so that the denominator * in the variance computation equals the length of the input vector minus one, use
-     *   evaluate(values, MathUtils.normalizeArray(weights, values.length)); 
+     *   evaluate(values, MathArrays.normalizeArray(weights, values.length)); 
      * 
*

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

@@ -462,7 +462,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se * weights are to be treated as "expansion values," as will be the case if for example * the weights represent frequency counts. To normalize weights so that the denominator * in the variance computation equals the length of the input vector minus one, use
-     *   evaluate(values, MathUtils.normalizeArray(weights, values.length), mean); 
+     *   evaluate(values, MathArrays.normalizeArray(weights, values.length), mean); 
      * 
*

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

@@ -539,7 +539,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se * weights are to be treated as "expansion values," as will be the case if for example * the weights represent frequency counts. To normalize weights so that the denominator * in the variance computation equals the length of the input vector minus one, use
-     *   evaluate(values, MathUtils.normalizeArray(weights, values.length), mean); 
+     *   evaluate(values, MathArrays.normalizeArray(weights, values.length), mean); 
      * 
*

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

diff --git a/src/main/java/org/apache/commons/math/util/MathArrays.java b/src/main/java/org/apache/commons/math/util/MathArrays.java index 03ff56b92..695b5a21f 100644 --- a/src/main/java/org/apache/commons/math/util/MathArrays.java +++ b/src/main/java/org/apache/commons/math/util/MathArrays.java @@ -26,6 +26,9 @@ import org.apache.commons.math.exception.DimensionMismatchException; import org.apache.commons.math.exception.MathInternalError; import org.apache.commons.math.exception.NonMonotonicSequenceException; import org.apache.commons.math.exception.NullArgumentException; +import org.apache.commons.math.exception.MathIllegalArgumentException; +import org.apache.commons.math.exception.util.LocalizedFormats; +import org.apache.commons.math.exception.MathArithmeticException; /** * Arrays utilities. @@ -1024,4 +1027,57 @@ public class MathArrays { } return true; } + + /** + * Normalizes an array to make it sum to a specified value. + * Returns the result of the transformation
+      *    x |-> x * normalizedSum / sum
+      * 
+ * applied to each non-NaN element x of the input array, where sum is the + * sum of the non-NaN entries in the input array.

+ * + *

Throws IllegalArgumentException if {@code normalizedSum} is infinite + * or NaN and ArithmeticException if the input array contains any infinite elements + * or sums to 0.

+ * + *

Ignores (i.e., copies unchanged to the output array) NaNs in the input array.

+ * + * @param values Input array to be normalized + * @param normalizedSum Target sum for the normalized array + * @return the normalized array. + * @throws MathArithmeticException if the input array contains infinite + * elements or sums to zero. + * @throws MathIllegalArgumentException if the target sum is infinite or {@code NaN}. + * @since 2.1 + */ + public static double[] normalizeArray(double[] values, double normalizedSum) { + if (Double.isInfinite(normalizedSum)) { + throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_INFINITE); + } + if (Double.isNaN(normalizedSum)) { + throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_NAN); + } + double sum = 0d; + final int len = values.length; + double[] out = new double[len]; + for (int i = 0; i < len; i++) { + if (Double.isInfinite(values[i])) { + throw new MathIllegalArgumentException(LocalizedFormats.INFINITE_ARRAY_ELEMENT, values[i], i); + } + if (!Double.isNaN(values[i])) { + sum += values[i]; + } + } + if (sum == 0) { + throw new MathArithmeticException(LocalizedFormats.ARRAY_SUMS_TO_ZERO); + } + for (int i = 0; i < len; i++) { + if (Double.isNaN(values[i])) { + out[i] = Double.NaN; + } else { + out[i] = values[i] * normalizedSum / sum; + } + } + return out; + } } diff --git a/src/main/java/org/apache/commons/math/util/MathUtils.java b/src/main/java/org/apache/commons/math/util/MathUtils.java index 00e6172e6..67d60fd7f 100644 --- a/src/main/java/org/apache/commons/math/util/MathUtils.java +++ b/src/main/java/org/apache/commons/math/util/MathUtils.java @@ -936,58 +936,6 @@ public final class MathUtils { return a - p * FastMath.floor((a - offset) / p) - offset; } - /** - *

Normalizes an array to make it sum to a specified value. - * Returns the result of the transformation

-      *    x |-> x * normalizedSum / sum
-      * 
- * applied to each non-NaN element x of the input array, where sum is the - * sum of the non-NaN entries in the input array.

- * - *

Throws IllegalArgumentException if {@code normalizedSum} is infinite - * or NaN and ArithmeticException if the input array contains any infinite elements - * or sums to 0

- * - *

Ignores (i.e., copies unchanged to the output array) NaNs in the input array.

- * - * @param values input array to be normalized - * @param normalizedSum target sum for the normalized array - * @return normalized array - * @throws MathArithmeticException if the input array contains infinite elements or sums to zero - * @throws MathIllegalArgumentException if the target sum is infinite or NaN - * @since 2.1 - */ - public static double[] normalizeArray(double[] values, double normalizedSum) { - if (Double.isInfinite(normalizedSum)) { - throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_INFINITE); - } - if (Double.isNaN(normalizedSum)) { - throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_NAN); - } - double sum = 0d; - final int len = values.length; - double[] out = new double[len]; - for (int i = 0; i < len; i++) { - if (Double.isInfinite(values[i])) { - throw new MathIllegalArgumentException(LocalizedFormats.INFINITE_ARRAY_ELEMENT, values[i], i); - } - if (!Double.isNaN(values[i])) { - sum += values[i]; - } - } - if (sum == 0) { - throw new MathArithmeticException(LocalizedFormats.ARRAY_SUMS_TO_ZERO); - } - for (int i = 0; i < len; i++) { - if (Double.isNaN(values[i])) { - out[i] = Double.NaN; - } else { - out[i] = values[i] * normalizedSum / sum; - } - } - return out; - } - /** * Round the given value to the specified number of decimal places. The * value is rounded using the {@link BigDecimal#ROUND_HALF_UP} method. diff --git a/src/test/java/org/apache/commons/math/stat/descriptive/moment/VarianceTest.java b/src/test/java/org/apache/commons/math/stat/descriptive/moment/VarianceTest.java index 1e85183fc..65b85818e 100644 --- a/src/test/java/org/apache/commons/math/stat/descriptive/moment/VarianceTest.java +++ b/src/test/java/org/apache/commons/math/stat/descriptive/moment/VarianceTest.java @@ -18,7 +18,7 @@ package org.apache.commons.math.stat.descriptive.moment; import org.apache.commons.math.stat.descriptive.StorelessUnivariateStatisticAbstractTest; import org.apache.commons.math.stat.descriptive.UnivariateStatistic; -import org.apache.commons.math.util.MathUtils; +import org.apache.commons.math.util.MathArrays; import org.junit.Assert; import org.junit.Test; @@ -110,7 +110,7 @@ public class VarianceTest extends StorelessUnivariateStatisticAbstractTest{ // 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, MathUtils.normalizeArray(identicalWeightsArray, testArray.length), + variance.evaluate(testArray, MathArrays.normalizeArray(identicalWeightsArray, testArray.length), 0, testArray.length), getTolerance()); } diff --git a/src/test/java/org/apache/commons/math/util/MathArraysTest.java b/src/test/java/org/apache/commons/math/util/MathArraysTest.java index c7f36a05c..74d29dbf0 100644 --- a/src/test/java/org/apache/commons/math/util/MathArraysTest.java +++ b/src/test/java/org/apache/commons/math/util/MathArraysTest.java @@ -17,7 +17,10 @@ import java.util.Arrays; import org.apache.commons.math.exception.NonMonotonicSequenceException; import org.apache.commons.math.exception.DimensionMismatchException; import org.apache.commons.math.exception.NullArgumentException; +import org.apache.commons.math.exception.MathArithmeticException; +import org.apache.commons.math.exception.MathIllegalArgumentException; import org.apache.commons.math.random.Well1024a; +import org.apache.commons.math.TestUtils; import org.junit.Assert; import org.junit.Test; @@ -586,4 +589,49 @@ public class MathArraysTest { Assert.assertFalse(MathArrays.equalsIncludingNaN(new double[] { 1d }, new double[] { FastMath.nextAfter(FastMath.nextAfter(1d, 2d), 2d) })); } + + @Test + public void testNormalizeArray() { + double[] testValues1 = new double[] {1, 1, 2}; + TestUtils.assertEquals( new double[] {.25, .25, .5}, + MathArrays.normalizeArray(testValues1, 1), + Double.MIN_VALUE); + + double[] testValues2 = new double[] {-1, -1, 1}; + TestUtils.assertEquals( new double[] {1, 1, -1}, + MathArrays.normalizeArray(testValues2, 1), + Double.MIN_VALUE); + + // Ignore NaNs + double[] testValues3 = new double[] {-1, -1, Double.NaN, 1, Double.NaN}; + TestUtils.assertEquals( new double[] {1, 1,Double.NaN, -1, Double.NaN}, + MathArrays.normalizeArray(testValues3, 1), + Double.MIN_VALUE); + + // Zero sum -> MathArithmeticException + double[] zeroSum = new double[] {-1, 1}; + try { + MathArrays.normalizeArray(zeroSum, 1); + Assert.fail("expecting MathArithmeticException"); + } catch (MathArithmeticException ex) {} + + // Infinite elements -> MathArithmeticException + double[] hasInf = new double[] {1, 2, 1, Double.NEGATIVE_INFINITY}; + try { + MathArrays.normalizeArray(hasInf, 1); + Assert.fail("expecting MathIllegalArgumentException"); + } catch (MathIllegalArgumentException ex) {} + + // Infinite target -> MathIllegalArgumentException + try { + MathArrays.normalizeArray(testValues1, Double.POSITIVE_INFINITY); + Assert.fail("expecting MathIllegalArgumentException"); + } catch (MathIllegalArgumentException ex) {} + + // NaN target -> MathIllegalArgumentException + try { + MathArrays.normalizeArray(testValues1, Double.NaN); + Assert.fail("expecting MathIllegalArgumentException"); + } catch (MathIllegalArgumentException ex) {} + } } diff --git a/src/test/java/org/apache/commons/math/util/MathUtilsTest.java b/src/test/java/org/apache/commons/math/util/MathUtilsTest.java index f1889f831..6d4754e6f 100644 --- a/src/test/java/org/apache/commons/math/util/MathUtilsTest.java +++ b/src/test/java/org/apache/commons/math/util/MathUtilsTest.java @@ -842,55 +842,6 @@ public final class MathUtilsTest { } } - @Test - public void testNormalizeArray() { - double[] testValues1 = new double[] {1, 1, 2}; - TestUtils.assertEquals( - new double[] {.25, .25, .5}, - MathUtils.normalizeArray(testValues1, 1), - Double.MIN_VALUE); - - double[] testValues2 = new double[] {-1, -1, 1}; - TestUtils.assertEquals( - new double[] {1, 1, -1}, - MathUtils.normalizeArray(testValues2, 1), - Double.MIN_VALUE); - - // Ignore NaNs - double[] testValues3 = new double[] {-1, -1, Double.NaN, 1, Double.NaN}; - TestUtils.assertEquals( - new double[] {1, 1,Double.NaN, -1, Double.NaN}, - MathUtils.normalizeArray(testValues3, 1), - Double.MIN_VALUE); - - // Zero sum -> MathArithmeticException - double[] zeroSum = new double[] {-1, 1}; - try { - MathUtils.normalizeArray(zeroSum, 1); - Assert.fail("expecting MathArithmeticException"); - } catch (MathArithmeticException ex) {} - - // Infinite elements -> MathArithmeticException - double[] hasInf = new double[] {1, 2, 1, Double.NEGATIVE_INFINITY}; - try { - MathUtils.normalizeArray(hasInf, 1); - Assert.fail("expecting MathIllegalArgumentException"); - } catch (MathIllegalArgumentException ex) {} - - // Infinite target -> MathIllegalArgumentException - try { - MathUtils.normalizeArray(testValues1, Double.POSITIVE_INFINITY); - Assert.fail("expecting MathIllegalArgumentException"); - } catch (MathIllegalArgumentException ex) {} - - // NaN target -> MathIllegalArgumentException - try { - MathUtils.normalizeArray(testValues1, Double.NaN); - Assert.fail("expecting MathIllegalArgumentException"); - } catch (MathIllegalArgumentException ex) {} - - } - @Test public void testRoundDouble() { double x = 1.234567890;