commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From er...@apache.org
Subject [2/7] [math] MATH-1341
Date Tue, 17 May 2016 13:28:20 GMT
MATH-1341

Unit tests.


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/412a8a0b
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/412a8a0b
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/412a8a0b

Branch: refs/heads/develop
Commit: 412a8a0ba61c84d71c0cc740ba7e50c10f3bf9ae
Parents: 363be2f
Author: Gilles <erans@apache.org>
Authored: Fri May 13 15:45:34 2016 +0200
Committer: Gilles <erans@apache.org>
Committed: Fri May 13 15:45:34 2016 +0200

----------------------------------------------------------------------
 .../RandomUtilsDataGeneratorAbstractTest.java   | 453 +++++++++++++++++++
 .../RandomUtilsDataGeneratorJDKRandomTest.java  |  31 ++
 ...omUtilsDataGeneratorJDKSecureRandomTest.java |  31 ++
 3 files changed, 515 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/412a8a0b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorAbstractTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorAbstractTest.java
b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorAbstractTest.java
new file mode 100644
index 0000000..f64d0fa
--- /dev/null
+++ b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorAbstractTest.java
@@ -0,0 +1,453 @@
+/*
+ * 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.random;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.List;
+
+import org.apache.commons.math4.TestUtils;
+import org.apache.commons.math4.exception.MathIllegalArgumentException;
+import org.apache.commons.math4.stat.Frequency;
+import org.apache.commons.math4.stat.inference.ChiSquareTest;
+import org.apache.commons.math4.util.FastMath;
+import org.apache.commons.math4.rng.UniformRandomProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test cases for the {@link RandomUtils#DataGenerator} class.
+ */
+public abstract class RandomUtilsDataGeneratorAbstractTest {
+    private final long smallSampleSize = 1000;
+    private final double[] expected = { 250, 250, 250, 250 };
+    private final int largeSampleSize = 10000;
+    private final String[] hex = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+                                   "a", "b", "c", "d", "e", "f" };
+    private final ChiSquareTest testStatistic = new ChiSquareTest();
+    /** Data generator. */
+    private final RandomUtils.DataGenerator randomData;
+
+    /**
+     * @param rng RNG.
+     */
+    protected RandomUtilsDataGeneratorAbstractTest(UniformRandomProvider rng) {
+        randomData = RandomUtils.createDataGenerator(rng);
+    }
+
+    @Test
+    public void testNextLongExtremeValues() {
+        long x = randomData.nextLong(Long.MIN_VALUE, Long.MAX_VALUE);
+        long y = randomData.nextLong(Long.MIN_VALUE, Long.MAX_VALUE);
+        Assert.assertFalse(x == y);
+    }
+
+    @Test
+    public void testNextUniformExtremeValues() {
+        double x = randomData.nextUniform(-Double.MAX_VALUE, Double.MAX_VALUE);
+        double y = randomData.nextUniform(-Double.MAX_VALUE, Double.MAX_VALUE);
+        Assert.assertFalse(x == y);
+        Assert.assertFalse(Double.isNaN(x));
+        Assert.assertFalse(Double.isNaN(y));
+        Assert.assertFalse(Double.isInfinite(x));
+        Assert.assertFalse(Double.isInfinite(y));
+    }
+
+    @Test
+    public void testNextLongIAE() {
+        try {
+            randomData.nextLong(4, 3);
+            Assert.fail("MathIllegalArgumentException expected");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+    }
+
+    @Test
+    public void testNextLongNegativeToPositiveRange() {
+        for (int i = 0; i < 5; i++) {
+            checkNextLongUniform(-3, 5);
+            checkNextLongUniform(-3, 6);
+        }
+    }
+
+    @Test
+    public void testNextLongNegativeRange() {
+        for (int i = 0; i < 5; i++) {
+            checkNextLongUniform(-7, -4);
+            checkNextLongUniform(-15, -2);
+            checkNextLongUniform(Long.MIN_VALUE + 1, Long.MIN_VALUE + 12);
+        }
+    }
+
+    @Test
+    public void testNextLongPositiveRange() {
+        for (int i = 0; i < 5; i++) {
+            checkNextLongUniform(0, 3);
+            checkNextLongUniform(2, 12);
+            checkNextLongUniform(Long.MAX_VALUE - 12, Long.MAX_VALUE - 1);
+        }
+    }
+
+    private void checkNextLongUniform(long min, long max) {
+        final Frequency freq = new Frequency();
+        for (int i = 0; i < smallSampleSize; i++) {
+            final long value = randomData.nextLong(min, max);
+            Assert.assertTrue("nextLong range: " + value + " " + min + " " + max,
+                              (value >= min) && (value <= max));
+            freq.addValue(value);
+        }
+        final int len = ((int) (max - min)) + 1;
+        final long[] observed = new long[len];
+        for (int i = 0; i < len; i++) {
+            observed[i] = freq.getCount(min + i);
+        }
+        final double[] expected = new double[len];
+        for (int i = 0; i < len; i++) {
+            expected[i] = 1d / len;
+        }
+
+        TestUtils.assertChiSquareAccept(expected, observed, 0.01);
+    }
+
+    @Test
+    public void testNextLongWideRange() {
+        long lower = -0x6543210FEDCBA987L;
+        long upper =  0x456789ABCDEF0123L;
+        long max = Long.MIN_VALUE;
+        long min = Long.MAX_VALUE;
+        for (int i = 0; i < 10000000; ++i) {
+            long r = randomData.nextLong(lower, upper);
+            max = FastMath.max(max, r);
+            min = FastMath.min(min, r);
+            Assert.assertTrue(r >= lower);
+            Assert.assertTrue(r <= upper);
+        }
+        double ratio = (((double) max)   - ((double) min)) /
+                       (((double) upper) - ((double) lower));
+        Assert.assertTrue(ratio > 0.99999);
+    }
+ 
+   /** Test dispersion and failure modes for "nextHex". */
+    @Test
+    public void testNextHexWithoutSha1() {
+        checkNextHex(false);
+    }
+    @Test
+    public void testNextHexWithSha1() {
+        checkNextHex(true);
+    }
+
+    /**
+     * @param useSha1 Alternative.
+     */
+    private void checkNextHex(boolean useSha1) {
+        try {
+            randomData.nextHexString(-1, useSha1);
+            Assert.fail("negative length supplied -- MathIllegalArgumentException expected");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+        try {
+            randomData.nextHexString(0, useSha1);
+            Assert.fail("zero length supplied -- MathIllegalArgumentException expected");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+        String hexString = randomData.nextHexString(3, useSha1);
+        if (hexString.length() != 3) {
+            Assert.fail("incorrect length for generated string");
+        }
+        hexString = randomData.nextHexString(1, useSha1);
+        if (hexString.length() != 1) {
+            Assert.fail("incorrect length for generated string");
+        }
+        try {
+            hexString = randomData.nextHexString(0, useSha1);
+            Assert.fail("zero length requested -- expecting MathIllegalArgumentException");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+        Frequency f = new Frequency();
+        for (int i = 0; i < smallSampleSize; i++) {
+            hexString = randomData.nextHexString(100, useSha1);
+            if (hexString.length() != 100) {
+                Assert.fail("incorrect length for generated string");
+            }
+            for (int j = 0; j < hexString.length(); j++) {
+                f.addValue(hexString.substring(j, j + 1));
+            }
+        }
+        double[] expected = new double[16];
+        long[] observed = new long[16];
+        for (int i = 0; i < 16; i++) {
+            expected[i] = (double) smallSampleSize * 100 / 16;
+            observed[i] = f.getCount(hex[i]);
+        }
+        TestUtils.assertChiSquareAccept(expected, observed, 0.001);
+    }
+
+    @Test
+    public void testNextUniformIAE() {
+        try {
+            randomData.nextUniform(4, 3);
+            Assert.fail("MathIllegalArgumentException expected");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+        try {
+            randomData.nextUniform(0, Double.POSITIVE_INFINITY);
+            Assert.fail("MathIllegalArgumentException expected");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+        try {
+            randomData.nextUniform(Double.NEGATIVE_INFINITY, 0);
+            Assert.fail("MathIllegalArgumentException expected");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+        try {
+            randomData.nextUniform(0, Double.NaN);
+            Assert.fail("MathIllegalArgumentException expected");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+        try {
+            randomData.nextUniform(Double.NaN, 0);
+            Assert.fail("MathIllegalArgumentException expected");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+    }
+
+    @Test
+    public void testNextUniformUniformPositiveBounds() {
+        for (int i = 0; i < 5; i++) {
+            checkNextUniformUniform(0, 10);
+        }
+    }
+
+    @Test
+    public void testNextUniformUniformNegativeToPositiveBounds() {
+        for (int i = 0; i < 5; i++) {
+            checkNextUniformUniform(-3, 5);
+        }
+    }
+
+    @Test
+    public void testNextUniformUniformNegaiveBounds() {
+        for (int i = 0; i < 5; i++) {
+            checkNextUniformUniform(-7, -3);
+        }
+    }
+
+    @Test
+    public void testNextUniformUniformMaximalInterval() {
+        for (int i = 0; i < 5; i++) {
+            checkNextUniformUniform(-Double.MAX_VALUE, Double.MAX_VALUE);
+        }
+    }
+
+    private void checkNextUniformUniform(double min, double max) {
+        // Set up bin bounds - min, binBound[0], ..., binBound[binCount-2], max
+        final int binCount = 5;
+        final double binSize = max / binCount - min/binCount; // Prevent overflow in extreme
value case
+        final double[] binBounds = new double[binCount - 1];
+        binBounds[0] = min + binSize;
+        for (int i = 1; i < binCount - 1; i++) {
+            binBounds[i] = binBounds[i - 1] + binSize;  // + instead of * to avoid overflow
in extreme case
+        }
+
+        final Frequency freq = new Frequency();
+        for (int i = 0; i < smallSampleSize; i++) {
+            final double value = randomData.nextUniform(min, max);
+            Assert.assertTrue("nextUniform range", (value > min) && (value <
max));
+            // Find bin
+            int j = 0;
+            while (j < binCount - 1 && value > binBounds[j]) {
+                j++;
+            }
+            freq.addValue(j);
+        }
+
+        final long[] observed = new long[binCount];
+        for (int i = 0; i < binCount; i++) {
+            observed[i] = freq.getCount(i);
+        }
+        final double[] expected = new double[binCount];
+        for (int i = 0; i < binCount; i++) {
+            expected[i] = 1d / binCount;
+        }
+
+        TestUtils.assertChiSquareAccept(expected, observed, 0.01);
+    }
+
+    /** test exclusive endpoints of nextUniform **/
+    @Test
+    public void testNextUniformExclusiveEndpoints() {
+        for (int i = 0; i < 1000; i++) {
+            double u = randomData.nextUniform(0.99, 1);
+            Assert.assertTrue(u > 0.99 && u < 1);
+        }
+    }
+
+    /** Tests for "nextSample" (sampling from Collection). */
+    @Test
+    public void testNextSample() {
+        Object[][] c = { { "0", "1" }, { "0", "2" }, { "0", "3" },
+                { "0", "4" }, { "1", "2" }, { "1", "3" }, { "1", "4" },
+                { "2", "3" }, { "2", "4" }, { "3", "4" } };
+        long[] observed = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+        double[] expected = { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 };
+
+        HashSet<Object> cPop = new HashSet<Object>(); // {0,1,2,3,4}
+        for (int i = 0; i < 5; i++) {
+            cPop.add(Integer.toString(i));
+        }
+
+        Object[] sets = new Object[10]; // 2-sets from 5
+        for (int i = 0; i < 10; i++) {
+            HashSet<Object> hs = new HashSet<Object>();
+            hs.add(c[i][0]);
+            hs.add(c[i][1]);
+            sets[i] = hs;
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            List<Object> cSamp = randomData.nextSample(cPop, 2);
+            observed[findSample(sets, cSamp)]++;
+        }
+
+        // Use ChiSquare dist with df = 10-1 = 9, alpha = 0.001
+        // Change to 21.67 for alpha = 0.01
+        Assert.assertTrue("chi-square test -- will fail about 1 in 1000 times",
+                          testStatistic.chiSquare(expected, observed) < 27.88);
+
+        // Make sure sample of size = size of collection returns same collection
+        HashSet<Object> hs = new HashSet<Object>();
+        hs.add("one");
+        List<Object> one = randomData.nextSample(hs, 1);
+        String oneString = (String) one.get(0);
+        if (one.size() != 1 ||
+            !oneString.equals("one")) {
+            Assert.fail("bad sample for set size = 1, sample size = 1");
+        }
+
+        // Make sure we fail for sample size > collection size.
+        try {
+            one = randomData.nextSample(hs, 2);
+            Assert.fail("sample size > set size, expecting MathIllegalArgumentException");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+
+        // Make sure we fail for empty collection.
+        try {
+            hs = new HashSet<Object>();
+            one = randomData.nextSample(hs, 0);
+            Assert.fail("n = k = 0, expecting MathIllegalArgumentException");
+        } catch (MathIllegalArgumentException ex) {
+            // ignored
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private int findSample(Object[] u, List<Object> sampList) {
+        Object[] samp = sampList.toArray(new Object[sampList.size()]);
+        for (int i = 0; i < u.length; i++) {
+            HashSet<Object> set = (HashSet<Object>) u[i];
+            HashSet<Object> sampSet = new HashSet<Object>();
+            for (int j = 0; j < samp.length; j++) {
+                sampSet.add(samp[j]);
+            }
+            if (set.equals(sampSet)) {
+                return i;
+            }
+        }
+        Assert.fail("sample not found:{" + samp[0] + "," + samp[1] + "}");
+        return -1;
+    }
+
+    /** tests for nextPermutation */
+    @Test
+    public void testNextPermutation() {
+        int[][] p = { { 0, 1, 2 }, { 0, 2, 1 }, { 1, 0, 2 }, { 1, 2, 0 },
+                      { 2, 0, 1 }, { 2, 1, 0 } };
+        long[] observed = { 0, 0, 0, 0, 0, 0 };
+        double[] expected = { 100, 100, 100, 100, 100, 100 };
+
+        for (int i = 0; i < 600; i++) {
+            int[] perm = randomData.nextPermutation(3, 3);
+            observed[findPerm(p, perm)]++;
+        }
+
+        String[] labels = {"{0, 1, 2}", "{ 0, 2, 1 }", "{ 1, 0, 2 }",
+                           "{ 1, 2, 0 }", "{ 2, 0, 1 }", "{ 2, 1, 0 }"};
+        TestUtils.assertChiSquareAccept(labels, expected, observed, 0.001);
+
+        // Check size = 1 boundary case
+        int[] perm = randomData.nextPermutation(1, 1);
+        if ((perm.length != 1) || (perm[0] != 0)) {
+            Assert.fail("bad permutation for n = 1, sample k = 1");
+
+            // Make sure we fail for k size > n
+            try {
+                perm = randomData.nextPermutation(2, 3);
+                Assert.fail("permutation k > n, expecting MathIllegalArgumentException");
+            } catch (MathIllegalArgumentException ex) {
+                // ignored
+            }
+
+            // Make sure we fail for n = 0
+            try {
+                perm = randomData.nextPermutation(0, 0);
+                Assert.fail("permutation k = n = 0, expecting MathIllegalArgumentException");
+            } catch (MathIllegalArgumentException ex) {
+                // ignored
+            }
+
+            // Make sure we fail for k < n < 0
+            try {
+                perm = randomData.nextPermutation(-1, -3);
+                Assert.fail("permutation k < n < 0, expecting MathIllegalArgumentException");
+            } catch (MathIllegalArgumentException ex) {
+                // ignored
+            }
+
+        }
+    }
+
+    private int findPerm(int[][] p, int[] samp) {
+        for (int i = 0; i < p.length; i++) {
+            boolean good = true;
+            for (int j = 0; j < samp.length; j++) {
+                if (samp[j] != p[i][j]) {
+                    good = false;
+                }
+            }
+            if (good) {
+                return i;
+            }
+        }
+        Assert.fail("permutation not found");
+        return -1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/412a8a0b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorJDKRandomTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorJDKRandomTest.java
b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorJDKRandomTest.java
new file mode 100644
index 0000000..a511826
--- /dev/null
+++ b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorJDKRandomTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.random;
+
+import java.util.Random;
+
+/**
+ * Test cases for the {@link RandomUtils#DataGenerator} class, using
+ * {@link Random} as the underlying source of randomness.
+ */
+public class RandomUtilsDataGeneratorJDKRandomTest
+    extends RandomUtilsDataGeneratorAbstractTest {
+
+    public RandomUtilsDataGeneratorJDKRandomTest() {
+        super(RandomUtils.asUniformRandomProvider(new Random(1000)));
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-math/blob/412a8a0b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorJDKSecureRandomTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorJDKSecureRandomTest.java
b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorJDKSecureRandomTest.java
new file mode 100644
index 0000000..3df4435
--- /dev/null
+++ b/src/test/java/org/apache/commons/math4/random/RandomUtilsDataGeneratorJDKSecureRandomTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.random;
+
+import java.security.SecureRandom;
+
+/**
+ * Test cases for the {@link RandomUtils#DataGenerator} class, using
+ * {@link SecureRandom} as the underlying source of randomness.
+ */
+public class RandomUtilsDataGeneratorJDKSecureRandomTest
+    extends RandomUtilsDataGeneratorAbstractTest {
+
+    public RandomUtilsDataGeneratorJDKSecureRandomTest() {
+        super(RandomUtils.asUniformRandomProvider(new SecureRandom(new byte[] {-12, 34, -56,
78})));
+    }
+}


Mime
View raw message