|
| 1 | +/* |
| 2 | + * JavaPermutationTools: A Java library for computation on permutations and sequences |
| 3 | + * Copyright 2005-2022 Vincent A. Cicirello, <https://www.cicirello.org/>. |
| 4 | + * |
| 5 | + * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). |
| 6 | + * |
| 7 | + * JavaPermutationTools is free software: you can |
| 8 | + * redistribute it and/or modify it under the terms of the GNU |
| 9 | + * General Public License as published by the Free Software |
| 10 | + * Foundation, either version 3 of the License, or (at your |
| 11 | + * option) any later version. |
| 12 | + * |
| 13 | + * JavaPermutationTools is distributed in the hope |
| 14 | + * that it will be useful, but WITHOUT ANY WARRANTY; without even |
| 15 | + * the implied warranty of MERCHANTABILITY or FITNESS FOR A |
| 16 | + * PARTICULAR PURPOSE. See the GNU General Public License for more |
| 17 | + * details. |
| 18 | + * |
| 19 | + * You should have received a copy of the GNU General Public License |
| 20 | + * along with JavaPermutationTools. If not, see <http://www.gnu.org/licenses/>. |
| 21 | + */ |
| 22 | +package org.cicirello.permutations; |
| 23 | + |
| 24 | +import java.util.SplittableRandom; |
| 25 | +import java.util.Random; |
| 26 | +import java.math.BigInteger; |
| 27 | +import org.junit.jupiter.api.*; |
| 28 | +import static org.junit.jupiter.api.Assertions.*; |
| 29 | + |
| 30 | +/** |
| 31 | + * JUnit tests for the constructors and methods of the Permutation class. |
| 32 | + */ |
| 33 | +public class PermutationConstructorRelatedTests extends SharedTestHelpersPermutation { |
| 34 | + |
| 35 | + // Set to false to enable chi square tests for randomness of constructor and |
| 36 | + // scramble, specifically for the constructor and scramble that uses ThreadLocalRandom |
| 37 | + // since it is not seedable. Tests passed repeatedly as of last update. |
| 38 | + // If that constructor or scramble is updated, then this flag should be set false to enable |
| 39 | + // tests (and reset true after passing). |
| 40 | + // Note: This doesn't disable those tests for the constructors/scramble methods |
| 41 | + // that use a source of randomness that is seedable. |
| 42 | + private static final boolean disableChiSquareTests = true; |
| 43 | + |
| 44 | + @Test |
| 45 | + public void testZeroLengthPermutations() { |
| 46 | + // different ways of constructing 0 length permutations. |
| 47 | + Permutation p1 = new Permutation(0); |
| 48 | + Permutation p2 = new Permutation(new int[] {}); |
| 49 | + Permutation p3 = new Permutation(0,0); |
| 50 | + Permutation copy = new Permutation(p1); |
| 51 | + |
| 52 | + // the above 4 should all be equivalent, so check |
| 53 | + assertEquals(p1,p2); |
| 54 | + assertEquals(p1,p3); |
| 55 | + assertEquals(p1,copy); |
| 56 | + assertEquals(p2,p3); |
| 57 | + assertEquals(p2,copy); |
| 58 | + assertEquals(p3,copy); |
| 59 | + } |
| 60 | + |
| 61 | + @Test |
| 62 | + public void testPermutationConstructor() { |
| 63 | + for (int n = 1; n <= 10; n++) { |
| 64 | + for (int i = 0; i < 10; i++) { |
| 65 | + Permutation p = new Permutation(n); |
| 66 | + validatePermutation(p, n); |
| 67 | + } |
| 68 | + } |
| 69 | + SplittableRandom r = new SplittableRandom(); |
| 70 | + for (int n = 1; n <= 10; n++) { |
| 71 | + for (int i = 0; i < 10; i++) { |
| 72 | + Permutation p = new Permutation(n, r); |
| 73 | + validatePermutation(p, n); |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + @Test |
| 79 | + public void testPermutationConstructorSpecific() { |
| 80 | + int fact = 1; |
| 81 | + for (int n = 1; n <= 6; n++) { |
| 82 | + fact *= n; |
| 83 | + for (int i = 0; i < fact; i++) { |
| 84 | + Permutation p = new Permutation(n, i); |
| 85 | + assertEquals(i, p.toInteger()); |
| 86 | + assertEquals(BigInteger.valueOf(i), p.toBigInteger()); |
| 87 | + validatePermutation(p, n); |
| 88 | + } |
| 89 | + } |
| 90 | + int n = 12; |
| 91 | + fact = 1; |
| 92 | + for (int i = 2; i <= n; i++) { |
| 93 | + fact *= i; |
| 94 | + } |
| 95 | + SplittableRandom r = new SplittableRandom(); |
| 96 | + for (int i = 0; i < 100; i++) { |
| 97 | + int which = r.nextInt(fact); |
| 98 | + Permutation p = new Permutation(n, which); |
| 99 | + assertEquals(which, p.toInteger()); |
| 100 | + assertEquals(BigInteger.valueOf(which), p.toBigInteger()); |
| 101 | + validatePermutation(p, n); |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + @Test |
| 106 | + public void testPermutationConstructorSpecificBigInt() { |
| 107 | + int fact = 1; |
| 108 | + for (int n = 1; n <= 6; n++) { |
| 109 | + fact *= n; |
| 110 | + for (int i = 0; i < fact; i++) { |
| 111 | + BigInteger big = BigInteger.valueOf(i); |
| 112 | + Permutation p = new Permutation(n, big); |
| 113 | + assertEquals(i, p.toInteger()); |
| 114 | + assertEquals(big, p.toBigInteger()); |
| 115 | + validatePermutation(p, n); |
| 116 | + } |
| 117 | + } |
| 118 | + int n = 12; |
| 119 | + fact = 1; |
| 120 | + for (int i = 2; i <= n; i++) { |
| 121 | + fact *= i; |
| 122 | + } |
| 123 | + SplittableRandom r = new SplittableRandom(); |
| 124 | + for (int i = 0; i < 100; i++) { |
| 125 | + int which = r.nextInt(fact); |
| 126 | + BigInteger bigWhich = BigInteger.valueOf(which); |
| 127 | + Permutation p = new Permutation(n, bigWhich); |
| 128 | + assertEquals(which, p.toInteger()); |
| 129 | + assertEquals(bigWhich, p.toBigInteger()); |
| 130 | + validatePermutation(p, n); |
| 131 | + } |
| 132 | + n = 20; |
| 133 | + BigInteger f = BigInteger.ONE; |
| 134 | + for (int i = 2; i <= n; i++) { |
| 135 | + f = f.multiply(BigInteger.valueOf(i)); |
| 136 | + } |
| 137 | + for (int i = 0; i < 20; i++) { |
| 138 | + BigInteger bigWhich = new BigInteger(f.bitLength()-1, new Random(42)); |
| 139 | + Permutation p = new Permutation(n, bigWhich); |
| 140 | + assertEquals(bigWhich, p.toBigInteger()); |
| 141 | + validatePermutation(p, n); |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + @Test |
| 146 | + public void testToIntegerExceptions() { |
| 147 | + UnsupportedOperationException thrown = assertThrows( |
| 148 | + UnsupportedOperationException.class, |
| 149 | + () -> (new Permutation(13)).toInteger() |
| 150 | + ); |
| 151 | + } |
| 152 | + |
| 153 | + @Test |
| 154 | + public void testPermutationCopyConstructor() { |
| 155 | + for (int n = 1; n <= 10; n++) { |
| 156 | + for (int i = 0; i < 10; i++) { |
| 157 | + Permutation p = new Permutation(n); |
| 158 | + Permutation copy = new Permutation(p); |
| 159 | + assertEquals(p, copy); |
| 160 | + assertEquals(p.hashCode(), copy.hashCode()); |
| 161 | + } |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + @Test |
| 166 | + public void testPermutationCopyMethod() { |
| 167 | + for (int n = 1; n <= 10; n++) { |
| 168 | + for (int i = 0; i < 10; i++) { |
| 169 | + Permutation p = new Permutation(n); |
| 170 | + Permutation copy = p.copy(); |
| 171 | + assertEquals(p, copy); |
| 172 | + assertTrue(p != copy); |
| 173 | + assertEquals(p.hashCode(), copy.hashCode()); |
| 174 | + } |
| 175 | + } |
| 176 | + } |
| 177 | + |
| 178 | + @Test |
| 179 | + public void testPermutationEqualsSpecialCases() { |
| 180 | + Permutation p = new Permutation(5); |
| 181 | + assertTrue(p.equals(p)); |
| 182 | + assertFalse(p.equals(null)); |
| 183 | + assertFalse(p.equals("hello")); |
| 184 | + } |
| 185 | + |
| 186 | + @Test |
| 187 | + public void testPermutationConstructorCopyPartial() { |
| 188 | + for (int n = 1; n <= 10; n++) { |
| 189 | + int[] forward = new int[n]; |
| 190 | + int[] backward = new int[n]; |
| 191 | + for (int i = 0; i < n; i++) { |
| 192 | + backward[n-1-i] = forward[i] = i; |
| 193 | + } |
| 194 | + Permutation p1 = new Permutation(forward); |
| 195 | + Permutation p2 = new Permutation(backward); |
| 196 | + for (int m = 0; m <= n; m++) { |
| 197 | + Permutation copy1 = new Permutation(p1, m); |
| 198 | + Permutation copy2 = new Permutation(p2, m); |
| 199 | + assertEquals(m, copy1.length()); |
| 200 | + assertEquals(m, copy2.length()); |
| 201 | + validatePermutation(copy1, m); |
| 202 | + validatePermutation(copy2, m); |
| 203 | + for (int i = 0; i < m; i++) { |
| 204 | + assertEquals(i, copy1.get(i)); |
| 205 | + assertEquals(m-1-i, copy2.get(i)); |
| 206 | + } |
| 207 | + } |
| 208 | + } |
| 209 | + } |
| 210 | + |
| 211 | + @Test |
| 212 | + public void testPermutationEquals() { |
| 213 | + Permutation p = new Permutation(10); |
| 214 | + for (int n = 1; n < 10; n++) { |
| 215 | + Permutation partialCopy = new Permutation(p, n); |
| 216 | + assertNotEquals(p, partialCopy); |
| 217 | + } |
| 218 | + Permutation copy = new Permutation(p); |
| 219 | + assertEquals(p, copy); |
| 220 | + assertNotEquals(new Permutation(new int[] {0, 1, 2, 3}), new Permutation(new int[] {3, 1, 2, 0})); |
| 221 | + } |
| 222 | + |
| 223 | + @Test |
| 224 | + public void testUniformityOfConstructors() { |
| 225 | + final int N = 12000; |
| 226 | + SplittableRandom r2 = new SplittableRandom(42); |
| 227 | + int tooHigh0 = 0; |
| 228 | + int tooHigh2 = 0; |
| 229 | + for (int k = 0; k < 100; k++) { |
| 230 | + int[] counts0 = new int[120]; |
| 231 | + int[] counts2 = new int[120]; |
| 232 | + for (int i = 0; i < N; i++) { |
| 233 | + Permutation p0 = new Permutation(5); |
| 234 | + Permutation p2 = new Permutation(5, r2); |
| 235 | + int j0 = p0.toInteger(); |
| 236 | + int j2 = p2.toInteger(); |
| 237 | + counts0[j0]++; |
| 238 | + counts2[j2]++; |
| 239 | + } |
| 240 | + if (chiSquare(counts0) > 146.567) tooHigh0++; |
| 241 | + if (chiSquare(counts2) > 146.567) tooHigh2++; |
| 242 | + } |
| 243 | + if (!disableChiSquareTests) { |
| 244 | + assertTrue(tooHigh0 <= 10); |
| 245 | + } |
| 246 | + assertTrue(tooHigh2 <= 10); |
| 247 | + } |
| 248 | +} |
0 commit comments