From 17c5b3f422009ece31ec1ba18633834724e7272f Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 14 Apr 2023 09:52:05 -0400 Subject: [PATCH 1/4] add tests --- .../PermutationHashCodeCacheTests.java | 782 ++++++++++++++++++ ...PermutationNoncontiguousScrambleTests.java | 4 - .../PermutationScrambleTests.java | 10 - 3 files changed, 782 insertions(+), 14 deletions(-) create mode 100644 src/test/java/org/cicirello/permutations/PermutationHashCodeCacheTests.java diff --git a/src/test/java/org/cicirello/permutations/PermutationHashCodeCacheTests.java b/src/test/java/org/cicirello/permutations/PermutationHashCodeCacheTests.java new file mode 100644 index 00000000..ce1edb2d --- /dev/null +++ b/src/test/java/org/cicirello/permutations/PermutationHashCodeCacheTests.java @@ -0,0 +1,782 @@ +/* + * JavaPermutationTools: A Java library for computation on permutations and sequences + * Copyright 2005-2023 Vincent A. Cicirello, . + * + * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). + * + * JavaPermutationTools is free software: you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * JavaPermutationTools is distributed in the hope + * that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with JavaPermutationTools. If not, see . + */ +package org.cicirello.permutations; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.SplittableRandom; +import org.junit.jupiter.api.*; + +/** JUnit tests for the caching and cache invalidation behavior of the hashCode() method. */ +public class PermutationHashCodeCacheTests { + + @Test + public void testCycle() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.cycle(new int[] {1, 3}); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.cycle(new int[] {1, 3, 5}); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testInvert() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.invert(); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testRemoveAndInsert() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(1, 4); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(4, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(1, 2); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(2, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testRemoveAndInsertSize() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(1, 1, 4); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(4, 1, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(1, 1, 2); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(2, 1, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(1, 2, 5); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(5, 2, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.removeAndInsert(2, 2, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testReverse() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.reverse(); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testReverseParams() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.reverse(1, 2); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.reverse(2, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.reverse(1, 5); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.reverse(5, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testRotate() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.rotate(1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.rotate(-1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.rotate(3); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testScramble() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(false); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(true); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + SplittableRandom rand = new SplittableRandom(73); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(rand); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(rand, false); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(rand, true); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testScrambleTwoIndexes() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(1, 2); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(2, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(1, 5); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(5, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + SplittableRandom rand = new SplittableRandom(73); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(1, 2, rand); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(2, 1, rand); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(1, 5, rand); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(5, 1, rand); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testScrambleIndexes() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(new int[] {1, 5}); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(new int[] {5, 1}); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(new int[] {1, 5, 3, 7}); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + SplittableRandom rand = new SplittableRandom(73); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(new int[] {1, 5}, rand); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(new int[] {5, 1}, rand); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.scramble(new int[] {1, 5, 3, 7}, rand); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testSet() { + Permutation p = new Permutation(5, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.set(new int[] {0, 1, 2, 3, 4}); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testSwap() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swap(1, 5); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swap(5, 1); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testSwapBlocks() { + Permutation p = new Permutation(10, new SplittableRandom(42)); + Permutation original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 1, 2, 2); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 1, 4, 4); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 1, 2, 4); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 3, 4, 4); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 1, 4, 6); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 3, 7, 7); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 3, 4, 6); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 3, 6, 8); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 3, 4, 7); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 4, 5, 7); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 3, 6, 9); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + + original = new Permutation(p); + assertEquals(original, p); + assertEquals(original.hashCode(), p.hashCode()); + assertEquals(original.hashCode(), p.hashCode()); + p.swapBlocks(1, 4, 7, 9); + assertNotEquals(original, p); + assertNotEquals(original.hashCode(), p.hashCode()); + assertNotEquals(original.hashCode(), p.hashCode()); + } + + @Test + public void testApplyBinary() { + Permutation p1 = new Permutation(5, new SplittableRandom(42)); + Permutation original1 = new Permutation(p1); + Permutation p2 = new Permutation(5, new SplittableRandom(73)); + Permutation original2 = new Permutation(p2); + assertEquals(original1, p1); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original2, p2); + assertEquals(original2.hashCode(), p2.hashCode()); + assertEquals(original2.hashCode(), p2.hashCode()); + p1.apply( + (raw1, raw2) -> { + for (int i = 0; i < raw1.length; i++) { + raw1[i] = raw2[i] = i; + } + }, + p2); + assertNotEquals(original1, p1); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original2, p2); + assertNotEquals(original2.hashCode(), p2.hashCode()); + assertNotEquals(original2.hashCode(), p2.hashCode()); + } + + @Test + public void testApplyBinaryValidate() { + Permutation p1 = new Permutation(5, new SplittableRandom(42)); + Permutation original1 = new Permutation(p1); + Permutation p2 = new Permutation(5, new SplittableRandom(73)); + Permutation original2 = new Permutation(p2); + assertEquals(original1, p1); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original2, p2); + assertEquals(original2.hashCode(), p2.hashCode()); + assertEquals(original2.hashCode(), p2.hashCode()); + p1.applyThenValidate( + (raw1, raw2) -> { + for (int i = 0; i < raw1.length; i++) { + raw1[i] = raw2[i] = i; + } + }, + p2); + assertNotEquals(original1, p1); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original2, p2); + assertNotEquals(original2.hashCode(), p2.hashCode()); + assertNotEquals(original2.hashCode(), p2.hashCode()); + } + + @Test + public void testApplyBinaryFull() { + Permutation p1 = new Permutation(5, new SplittableRandom(42)); + Permutation original1 = new Permutation(p1); + Permutation p2 = new Permutation(5, new SplittableRandom(73)); + Permutation original2 = new Permutation(p2); + assertEquals(original1, p1); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original2, p2); + assertEquals(original2.hashCode(), p2.hashCode()); + assertEquals(original2.hashCode(), p2.hashCode()); + p1.apply( + (raw1, raw2, o1, o2) -> { + for (int i = 0; i < raw1.length; i++) { + raw1[i] = raw2[i] = i; + } + }, + p2); + assertNotEquals(original1, p1); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original2, p2); + assertNotEquals(original2.hashCode(), p2.hashCode()); + assertNotEquals(original2.hashCode(), p2.hashCode()); + } + + @Test + public void testApplyBinaryFullValidate() { + Permutation p1 = new Permutation(5, new SplittableRandom(42)); + Permutation original1 = new Permutation(p1); + Permutation p2 = new Permutation(5, new SplittableRandom(73)); + Permutation original2 = new Permutation(p2); + assertEquals(original1, p1); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original2, p2); + assertEquals(original2.hashCode(), p2.hashCode()); + assertEquals(original2.hashCode(), p2.hashCode()); + p1.applyThenValidate( + (raw1, raw2, o1, o2) -> { + for (int i = 0; i < raw1.length; i++) { + raw1[i] = raw2[i] = i; + } + }, + p2); + assertNotEquals(original1, p1); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original2, p2); + assertNotEquals(original2.hashCode(), p2.hashCode()); + assertNotEquals(original2.hashCode(), p2.hashCode()); + } + + @Test + public void testApplyUnary() { + Permutation p1 = new Permutation(5, new SplittableRandom(42)); + Permutation original1 = new Permutation(p1); + assertEquals(original1, p1); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original1.hashCode(), p1.hashCode()); + p1.apply( + raw1 -> { + for (int i = 0; i < raw1.length; i++) { + raw1[i] = i; + } + }); + assertNotEquals(original1, p1); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original1.hashCode(), p1.hashCode()); + } + + @Test + public void testApplyUnaryValidate() { + Permutation p1 = new Permutation(5, new SplittableRandom(42)); + Permutation original1 = new Permutation(p1); + assertEquals(original1, p1); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original1.hashCode(), p1.hashCode()); + p1.applyThenValidate( + raw1 -> { + for (int i = 0; i < raw1.length; i++) { + raw1[i] = i; + } + }); + assertNotEquals(original1, p1); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original1.hashCode(), p1.hashCode()); + } + + @Test + public void testApplyUnaryFull() { + Permutation p1 = new Permutation(5, new SplittableRandom(42)); + Permutation original1 = new Permutation(p1); + assertEquals(original1, p1); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original1.hashCode(), p1.hashCode()); + p1.apply( + (int[] raw1, Permutation o1) -> { + for (int i = 0; i < raw1.length; i++) { + raw1[i] = i; + } + }); + assertNotEquals(original1, p1); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original1.hashCode(), p1.hashCode()); + } + + @Test + public void testApplyUnaryFullValidate() { + Permutation p1 = new Permutation(5, new SplittableRandom(42)); + Permutation original1 = new Permutation(p1); + assertEquals(original1, p1); + assertEquals(original1.hashCode(), p1.hashCode()); + assertEquals(original1.hashCode(), p1.hashCode()); + p1.applyThenValidate( + (int[] raw1, Permutation o1) -> { + for (int i = 0; i < raw1.length; i++) { + raw1[i] = i; + } + }); + assertNotEquals(original1, p1); + assertNotEquals(original1.hashCode(), p1.hashCode()); + assertNotEquals(original1.hashCode(), p1.hashCode()); + } +} diff --git a/src/test/java/org/cicirello/permutations/PermutationNoncontiguousScrambleTests.java b/src/test/java/org/cicirello/permutations/PermutationNoncontiguousScrambleTests.java index 90e90658..775680b5 100644 --- a/src/test/java/org/cicirello/permutations/PermutationNoncontiguousScrambleTests.java +++ b/src/test/java/org/cicirello/permutations/PermutationNoncontiguousScrambleTests.java @@ -34,12 +34,10 @@ public void testNoncontiguousScrambleLengthOne() { SplittableRandom r2 = new SplittableRandom(42); // Verify does nothing if permutation length < 2. Permutation p = new Permutation(1); - int oldHash = p.hashCode(); int[] indexes = {0}; for (int i = 0; i < 5; i++) { p.scramble(indexes, r2); assertEquals(0, p.get(0)); - assertEquals(oldHash, p.hashCode()); p.scramble(indexes); assertEquals(0, p.get(0)); } @@ -57,11 +55,9 @@ public void testNoncontiguousScrambleTwoIndexes() { shouldChange[indexes[0]] = shouldChange[indexes[1]] = true; Permutation p = new Permutation(n, 0); Permutation p0 = new Permutation(p); - assertEquals(p0.hashCode(), p.hashCode()); p.scramble(indexes, r2); assertEquals(0, p.get(n - 1)); assertEquals(n - 1, p.get(0)); - assertNotEquals(p0.hashCode(), p.hashCode()); for (int i = 0; i < n; i++) { if (!shouldChange[i]) { assertEquals(p0.get(i), p.get(i)); diff --git a/src/test/java/org/cicirello/permutations/PermutationScrambleTests.java b/src/test/java/org/cicirello/permutations/PermutationScrambleTests.java index f0aa2948..44bb700c 100644 --- a/src/test/java/org/cicirello/permutations/PermutationScrambleTests.java +++ b/src/test/java/org/cicirello/permutations/PermutationScrambleTests.java @@ -58,9 +58,7 @@ public void testScramble() { p.scramble(); validatePermutation(p, i); original = new Permutation(p); - assertEquals(original.hashCode(), p.hashCode()); p.scramble(r2); - if (i >= 7) assertNotEquals(original.hashCode(), p.hashCode()); validatePermutation(p, i); p.scramble(false); @@ -70,21 +68,17 @@ public void testScramble() { validatePermutation(p, i); original = new Permutation(p); - assertEquals(original.hashCode(), p.hashCode()); p.scramble(true); validatePermutation(p, i); if (i > 1) { assertNotEquals(original, p); - assertNotEquals(original.hashCode(), p.hashCode()); } original = new Permutation(p); - assertEquals(original.hashCode(), p.hashCode()); p.scramble(r2, true); validatePermutation(p, i); if (i > 1) { assertNotEquals(original, p); - assertNotEquals(original.hashCode(), p.hashCode()); } } } @@ -96,20 +90,16 @@ public void testScrambleFromItoJ() { for (int n = 4; n < 8; n++) { Permutation p = new Permutation(n, r2); Permutation original = new Permutation(p); - assertEquals(original.hashCode(), p.hashCode()); p.scramble(1, n - 2); validatePermutation(p, n); assertNotEquals(original, p); - assertNotEquals(original.hashCode(), p.hashCode()); assertEquals(original.get(0), p.get(0)); assertEquals(original.get(n - 1), p.get(n - 1)); original = new Permutation(p); - assertEquals(original.hashCode(), p.hashCode()); p.scramble(1, n - 2, r2); validatePermutation(p, n); assertNotEquals(original, p); - assertNotEquals(original.hashCode(), p.hashCode()); assertEquals(original.get(0), p.get(0)); assertEquals(original.get(n - 1), p.get(n - 1)); From 8d518f508ca8bbaa149be98ed3adaecef6846e23 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 14 Apr 2023 10:09:27 -0400 Subject: [PATCH 2/4] optimize swapBlocks and scramble --- src/main/java/org/cicirello/permutations/Permutation.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/cicirello/permutations/Permutation.java b/src/main/java/org/cicirello/permutations/Permutation.java index 826176c1..ae8aa623 100644 --- a/src/main/java/org/cicirello/permutations/Permutation.java +++ b/src/main/java/org/cicirello/permutations/Permutation.java @@ -539,10 +539,12 @@ public void scramble(int i, int j, RandomGenerator r) { if (i == j) { return; } - int k = j; + int k; if (i > j) { k = i; i = j; + } else { + k = j; } boolean changed = false; for (; k > i + 1; k--) { @@ -745,12 +747,12 @@ public void swapBlocks(int a, int b, int i, int j) { // blocks are adjacent removeAndInsert(i, j - i + 1, a); } else { - int[] temp = new int[j - a + 1]; + int[] temp = new int[j - b]; int k = j - i + 1; System.arraycopy(permutation, i, temp, 0, k); int m = i - b - 1; System.arraycopy(permutation, b + 1, temp, k, m); - System.arraycopy(permutation, a, temp, k + m, b - a + 1); + System.arraycopy(permutation, a, permutation, a + temp.length, b - a + 1); System.arraycopy(temp, 0, permutation, a, temp.length); hashCodeIsCached = false; } From 4b53ecd4ef3adee2acd9c4c1f0421285790b0aef Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 14 Apr 2023 10:41:20 -0400 Subject: [PATCH 3/4] refactor reverse --- .../cicirello/permutations/Permutation.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/cicirello/permutations/Permutation.java b/src/main/java/org/cicirello/permutations/Permutation.java index ae8aa623..cce90b2f 100644 --- a/src/main/java/org/cicirello/permutations/Permutation.java +++ b/src/main/java/org/cicirello/permutations/Permutation.java @@ -760,9 +760,7 @@ public void swapBlocks(int a, int b, int i, int j) { /** Reverses the order of the elements in the permutation. */ public void reverse() { - for (int i = 0, j = permutation.length - 1; i < j; i++, j--) { - internalSwap(i, j); - } + internalReverse(0, permutation.length - 1); hashCodeIsCached = false; } @@ -776,13 +774,9 @@ public void reverse() { */ public void reverse(int i, int j) { if (i > j) { - for (; i > j; i--, j++) { - internalSwap(i, j); - } + internalReverse(j, i); } else { - for (; i < j; i++, j--) { - internalSwap(i, j); - } + internalReverse(i, j); } hashCodeIsCached = false; } @@ -959,6 +953,12 @@ private boolean validate(int[] p) { return true; } + private void internalReverse(int i, int j) { + for (; i < j; i++, j--) { + internalSwap(i, j); + } + } + /* * Use internally, such as from reverse, etc to avoid * repeatedly invalidating hashCode cache (as well as from From dead060840a32d8546ffbae2a7a7fd5a597efa9c Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 14 Apr 2023 10:46:42 -0400 Subject: [PATCH 4/4] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aee9edb..b24dab27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] - 2023-04-13 +## [Unreleased] - 2023-04-14 ### Added ### Changed +* Optimized or otherwise refactored for code quality the scramble, reverse, and swapBlocks methods of the Permutation class. ### Deprecated