From 1ee73c1c6b5f32b34cc1c7c130b8bbdffeb6beb6 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Thu, 28 Jan 2021 14:50:12 -0500 Subject: [PATCH 01/22] Minor optimization --- CHANGELOG.md | 4 +++- src/org/cicirello/permutations/Permutation.java | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3ea48a3..b8c3c268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,14 @@ 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] - 2021-01-27 +## [Unreleased] - 2021-01-28 ### Added +* Test cases added to improve test coverage. ### Changed * Modified API documentation website (https://jpt.cicirello.org/) to improve browsing on mobile devices. +* Minor optimizations in Permutation class. ### Deprecated diff --git a/src/org/cicirello/permutations/Permutation.java b/src/org/cicirello/permutations/Permutation.java index 459486ad..ab106bc0 100644 --- a/src/org/cicirello/permutations/Permutation.java +++ b/src/org/cicirello/permutations/Permutation.java @@ -1,5 +1,5 @@ /* - * Copyright 2005, 2010, 2014-2019 Vincent A. Cicirello, . + * Copyright 2005, 2010, 2014-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -38,8 +38,7 @@ * manipulate permutations in a variety of ways. * * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 9.23.2019 - * @since 1.0 + * @version 1.28.2021 */ public final class Permutation implements Serializable, Iterable, Copyable { @@ -777,7 +776,7 @@ public void removeAndInsert(int i, int size, int j) { System.arraycopy(permutation, j, temp, 0, i-j); System.arraycopy(permutation, i, permutation, j, size); System.arraycopy(temp, 0, permutation, j+size, i-j); - } else if (i < j) { + } else { // Condition is implied by above: if (i < j) int[] temp = new int[size]; System.arraycopy(permutation, i, temp, 0, size); System.arraycopy(permutation, i+size, permutation, i, j-i); From f7c9326c264550f4e1890d8063a607d863c1011a Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Thu, 28 Jan 2021 15:48:07 -0500 Subject: [PATCH 02/22] minor bug fix --- CHANGELOG.md | 1 + src/org/cicirello/permutations/Permutation.java | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8c3c268..3ae98642 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Removed the zip files generated by javadoc of the indexes for the api website. These are not needed for search functionality, as javadoc also stores and uses the js files contained in these zips. Later versions of javadoc no longer generate these. Also gitignored these to prevent future storage. ### Fixed +* Bug in Permutation.toString which was inserting an extra space at end. ### CI/CD * Migrated build process from Ant to Maven, including GitHub workflows. diff --git a/src/org/cicirello/permutations/Permutation.java b/src/org/cicirello/permutations/Permutation.java index ab106bc0..414c39a7 100644 --- a/src/org/cicirello/permutations/Permutation.java +++ b/src/org/cicirello/permutations/Permutation.java @@ -827,8 +827,11 @@ public Iterator iterator() { @Override public String toString() { String permS = ""; - for (int i : permutation) { - permS += (i + " "); + if (permutation.length > 0) { + permS += permutation[0]; + for (int i = 1; i < permutation.length; i++) { + permS += " " + permutation[i]; + } } return permS; } From 57f83593422645c8f9a815194c7f8bb8c9d45e13 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Thu, 28 Jan 2021 15:48:27 -0500 Subject: [PATCH 03/22] Test coverage for Permutation class now 100% --- .../permutations/PermutationTestCases.java | 207 +++++++++++++++++- 1 file changed, 201 insertions(+), 6 deletions(-) diff --git a/tests/org/cicirello/permutations/PermutationTestCases.java b/tests/org/cicirello/permutations/PermutationTestCases.java index a8f2835f..52734b51 100644 --- a/tests/org/cicirello/permutations/PermutationTestCases.java +++ b/tests/org/cicirello/permutations/PermutationTestCases.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -154,14 +154,42 @@ public void testPermutationConstructorSpecificBigInt() { } } + @Test + public void testToIntegerExceptions() { + UnsupportedOperationException thrown = assertThrows( + UnsupportedOperationException.class, + () -> (new Permutation(13)).toInteger() + ); + } + @Test public void testPermutationConstructorFromArray() { int[][] arrays = { { 0 }, { 1, 0 }, { 1, 0, 2 }, { 3, 1, 2, 0 } }; + String[] str = {"0", "1 0", "1 0 2", "3 1 2 0"}; + int s = 0; for (int[] a : arrays) { Permutation p = new Permutation(a.clone()); validatePermutation(p, a.length); for (int i = 0; i < a.length; i++) assertEquals("elements should be in same order", a[i], p.get(i)); - } + assertEquals(str[s], p.toString()); + s++; + } + assertEquals("", (new Permutation(0)).toString()); + final int[] negative = { 1, 4, -1, 0, 3}; + final int[] tooHigh = { 1, 4, 5, 0, 3}; + final int[] duplicate = { 1, 4, 2, 1, 3}; + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> new Permutation(negative) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> new Permutation(tooHigh) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> new Permutation(duplicate) + ); } @Test @@ -173,6 +201,26 @@ public void testPermutationSetFromArray() { validatePermutation(p, a.length); for (int i = 0; i < a.length; i++) assertEquals("elements should be in same order", a[i], p.get(i)); } + final int[] negative = { 1, 4, -1, 0, 3}; + final int[] tooHigh = { 1, 4, 5, 0, 3}; + final int[] duplicate = { 1, 4, 2, 1, 3}; + final int[] tooLong = { 1, 2, 4, 5, 0, 3}; + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(5)).set(negative) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(5)).set(tooHigh) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(5)).set(duplicate) + ); + assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(5)).set(tooLong) + ); } @Test @@ -236,6 +284,7 @@ public void testPermutationCopyConstructor() { Permutation p = new Permutation(n); Permutation copy = new Permutation(p); assertEquals("copy should create an identical copy", p, copy); + assertEquals(p.hashCode(), copy.hashCode()); } } } @@ -248,10 +297,19 @@ public void testPermutationCopyMethod() { Permutation copy = p.copy(); assertEquals("copy should create an identical copy", p, copy); assertTrue("copy should be a new object", p != copy); + assertEquals(p.hashCode(), copy.hashCode()); } } } + @Test + public void testPermutationEqualsSpecialCases() { + Permutation p = new Permutation(5); + assertTrue(p.equals(p)); + assertFalse(p.equals(null)); + assertFalse(p.equals("hello")); + } + @Test public void testPermutationConstructorCopyPartial() { for (int n = 1; n <= 10; n++) { @@ -353,6 +411,12 @@ public void testToArray() { int[] result = p.toArray(array); assertTrue("Should use the array parameter if correct length", result == array); assertArrayEquals("should be equal to current state", init, result); + + array = new int[7]; + result = null; + result = p.toArray(array); + assertFalse("Should construct new array if the array parameter wrong length", result == array); + assertArrayEquals("should be equal to current state", init, result); } @Test @@ -400,6 +464,14 @@ public void testGetRange() { } } } + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(3)).get(1,0) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(3)).get(1,0, null) + ); } @Test @@ -407,7 +479,6 @@ public void testPermutationRemoveInsert() { Permutation p = new Permutation(5); for (int i = 0; i < p.length(); i++) { for (int j = 0; j < p.length(); j++) { - if (i==j) continue; Permutation copy = new Permutation(p); copy.removeAndInsert(i, j); if (i < j) { @@ -421,7 +492,7 @@ public void testPermutationRemoveInsert() { for (int k = j+1; k < p.length(); k++) { assertEquals("elements after insertion point should not change", p.get(k), copy.get(k)); } - } else { + } else if (i > j) { for (int k = 0; k < j; k++) { assertEquals("elements before insertion point should not change", p.get(k), copy.get(k)); } @@ -432,6 +503,8 @@ public void testPermutationRemoveInsert() { for (int k = i+1; k < p.length(); k++) { assertEquals("elements after removal point should not change", p.get(k), copy.get(k)); } + } else { + assertEquals(p, copy); } } } @@ -471,6 +544,13 @@ public void testPermutationBlockRemoveInsert() { mutant = new Permutation(p); mutant.removeAndInsert(7, 2, 1); assertEquals("move 2 earlier", p6, mutant); + + mutant = new Permutation(p); + mutant.removeAndInsert(1, 0, 3); + assertEquals(p, mutant); + mutant = new Permutation(p); + mutant.removeAndInsert(1, 3, 1); + assertEquals(p, mutant); } @Test @@ -496,6 +576,19 @@ public void testPermutationReverse() { for (int i = k+1; i < p.length(); i++) { assertEquals("elements after should not change", p.get(i), copy.get(i)); } + copy = new Permutation(p); + copy.reverse(k, j); + for (int i = 0; i < j; i++) { + assertEquals("elements before should not change", p.get(i), copy.get(i)); + } + shift = 0; + for (int i = j; i <= k; i++) { + assertEquals("elements should be reversed", p.get(i), copy.get(k-shift)); + shift++; + } + for (int i = k+1; i < p.length(); i++) { + assertEquals("elements after should not change", p.get(i), copy.get(i)); + } } } } @@ -511,11 +604,20 @@ public void testPermutationRotate() { assertEquals("elements should be left rotated " + r + " places", p.get(j), copy.get(i)); } } + Permutation copy = new Permutation(p); + copy.rotate(p.length()); + assertEquals(p, copy); + copy = new Permutation(p); + copy.rotate(-1); + for (int i = 1; i < p.length(); i++) { + assertEquals("elements should be RIGHT rotated 1 place", p.get(i-1), copy.get(i)); + } + assertEquals("elements should be RIGHT rotated 1 place", p.get(p.length()-1), copy.get(0)); } @Test public void testSwap() { - for (int i = 2; i <= 10; i++) { + for (int i = 1; i <= 10; i++) { Permutation p = new Permutation(i); Permutation p2 = new Permutation(p); p2.swap(0, i-1); @@ -525,7 +627,7 @@ public void testSwap() { assertEquals("non swapped elements should not change", p.get(j), p2.get(j)); } } - for (int i = 2; i <= 10; i++) { + for (int i = 1; i <= 10; i++) { Permutation p = new Permutation(i); Permutation p2 = new Permutation(p); p2.swap(i-1, 0); @@ -604,6 +706,26 @@ public void testSwapBlocks() { } } } + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(10)).swapBlocks(-1, 3, 5, 7) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(10)).swapBlocks(3, 2, 5, 7) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(10)).swapBlocks(1, 3, 3, 7) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(10)).swapBlocks(1, 3, 7, 6) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> (new Permutation(10)).swapBlocks(1, 3, 5, 10) + ); } @Test @@ -645,6 +767,12 @@ public void testScramble() { original = new Permutation(p); p.scramble(r2); validatePermutation(p, i); + p.scramble(false); + validatePermutation(p, i); + p.scramble(r1, false); + validatePermutation(p, i); + p.scramble(r2, false); + validatePermutation(p, i); original = new Permutation(p); p.scramble(true); validatePermutation(p, i); @@ -661,6 +789,73 @@ public void testScramble() { } } + @Test + public void testScrambleFromItoJ() { + Random r1 = new Random(); + SplittableRandom r2 = new SplittableRandom(); + for (int n = 4; n < 8; n++) { + Permutation p = new Permutation(n); + Permutation original = new Permutation(p); + p.scramble(1, n-2); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + assertEquals(original.get(0), p.get(0)); + assertEquals(original.get(n-1), p.get(n-1)); + original = new Permutation(p); + p.scramble(1, n-2, r1); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + assertEquals(original.get(0), p.get(0)); + assertEquals(original.get(n-1), p.get(n-1)); + original = new Permutation(p); + p.scramble(1, n-2, r2); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + assertEquals(original.get(0), p.get(0)); + assertEquals(original.get(n-1), p.get(n-1)); + original = new Permutation(p); + p.scramble(0, n-1); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + original = new Permutation(p); + p.scramble(0, n-1, r1); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + original = new Permutation(p); + p.scramble(0, n-1, r2); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + original = new Permutation(p); + p.scramble(1, 1, r2); + assertEquals(original, p); + original = new Permutation(p); + p.scramble(1, 1, r1); + assertEquals(original, p); + original = new Permutation(p); + p.scramble(1, 1); + assertEquals(original, p); + + original = new Permutation(p); + p.scramble(n-2, 1); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + assertEquals(original.get(0), p.get(0)); + assertEquals(original.get(n-1), p.get(n-1)); + original = new Permutation(p); + p.scramble(n-2, 1, r1); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + assertEquals(original.get(0), p.get(0)); + assertEquals(original.get(n-1), p.get(n-1)); + original = new Permutation(p); + p.scramble(n-2, 1, r2); + validatePermutation(p, n); + if (n > 1) assertNotEquals(original, p); + assertEquals(original.get(0), p.get(0)); + assertEquals(original.get(n-1), p.get(n-1)); + } + } + @Test public void testUniformityOfConstructors() { final int N = 12000; From b9606eb121e4bb34ecc9be3b04b2df8e87971197 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Thu, 28 Jan 2021 15:59:20 -0500 Subject: [PATCH 04/22] Improved test coverage PermutationIterator test coverage now 100% --- .../permutations/PermutationTestCases.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/org/cicirello/permutations/PermutationTestCases.java b/tests/org/cicirello/permutations/PermutationTestCases.java index 52734b51..605709dd 100644 --- a/tests/org/cicirello/permutations/PermutationTestCases.java +++ b/tests/org/cicirello/permutations/PermutationTestCases.java @@ -25,6 +25,7 @@ import java.util.Random; import java.util.concurrent.ThreadLocalRandom; import java.math.BigInteger; +import java.util.NoSuchElementException; import org.junit.*; import static org.junit.Assert.*; @@ -749,6 +750,22 @@ public void testPermutationIterator() { } assertEquals("Should iterate over all permutations of given length", fact, count); } + final PermutationIterator iter = new PermutationIterator(4); + fact = 24; + boolean[] found = new boolean[fact]; + int count = 0; + while (iter.hasNext()) { + Permutation p = iter.next(); + int permID = p.toInteger(); + assertFalse("should not give same permutation more than once", found[permID]); + found[permID] = true; + count++; + } + assertEquals("Should iterate over all permutations of given length", fact, count); + NoSuchElementException thrown = assertThrows( + NoSuchElementException.class, + () -> iter.next() + ); } @Test From 6c01edb4759147ac2f386b4cdb4b2486307ce82f Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Thu, 28 Jan 2021 16:54:58 -0500 Subject: [PATCH 05/22] Validation checking for same length permutations --- CHANGELOG.md | 1 + .../AbstractPermutationDistanceMeasurer.java | 14 ++-------- .../distance/AcyclicEdgeDistance.java | 26 +++++++----------- .../distance/BlockInterchangeDistance.java | 14 ++++------ .../distance/CyclicEdgeDistance.java | 27 +++++++------------ .../distance/CyclicIndependentDistance.java | 14 +++++++--- .../CyclicIndependentDistanceDouble.java | 6 ++--- .../distance/CyclicRTypeDistance.java | 27 +++++++------------ .../CyclicReversalIndependentDistance.java | 14 +++++++--- ...clicReversalIndependentDistanceDouble.java | 6 ++--- .../distance/DeviationDistance.java | 19 +++++-------- .../distance/DeviationDistanceNormalized.java | 15 ++--------- .../DeviationDistanceNormalized2005.java | 14 ++-------- .../permutations/distance/EditDistance.java | 11 +++++--- .../distance/ExactMatchDistance.java | 17 +++++------- .../distance/InterchangeDistance.java | 22 ++++++--------- .../distance/KendallTauDistance.java | 20 +++++--------- .../permutations/distance/LeeDistance.java | 21 ++++++--------- ...NormalizedPermutationDistanceMeasurer.java | 6 ++--- ...izedPermutationDistanceMeasurerDouble.java | 8 +++--- .../distance/PermutationDistanceMeasurer.java | 6 ++--- .../PermutationDistanceMeasurerDouble.java | 9 +++---- .../permutations/distance/RTypeDistance.java | 26 +++++++----------- .../distance/ReinsertionDistance.java | 18 +++++-------- .../distance/ReversalDistance.java | 20 ++++---------- .../distance/ReversalIndependentDistance.java | 14 +++++++--- .../ReversalIndependentDistanceDouble.java | 6 ++--- .../distance/ScrambleDistance.java | 11 ++------ .../distance/SquaredDeviationDistance.java | 17 +++++------- .../distance/PermutationDistanceTests.java | 2 +- 30 files changed, 167 insertions(+), 264 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae98642..90f0a3ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed * Bug in Permutation.toString which was inserting an extra space at end. +* Added validation checking for all permutation distance measures validating same length permutations (except for EditDistance which can handle that case). ### CI/CD * Migrated build process from Ant to Maven, including GitHub workflows. diff --git a/src/org/cicirello/permutations/distance/AbstractPermutationDistanceMeasurer.java b/src/org/cicirello/permutations/distance/AbstractPermutationDistanceMeasurer.java index e1126c54..139ceebf 100644 --- a/src/org/cicirello/permutations/distance/AbstractPermutationDistanceMeasurer.java +++ b/src/org/cicirello/permutations/distance/AbstractPermutationDistanceMeasurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, 2015, 2017-2019 Vincent A. Cicirello, . + * Copyright 2010, 2015, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -27,31 +27,21 @@ * where distance is an integer value. * * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ abstract class AbstractPermutationDistanceMeasurer implements PermutationDistanceMeasurer, NormalizedPermutationDistanceMeasurer { - /** - * {@inheritDoc} - */ @Override public final double distancef(Permutation p1, Permutation p2) { return distance(p1,p2); } - /** - * {@inheritDoc} - */ @Override public final double maxf(int length) { return max(length); } - /** - * {@inheritDoc} - */ @Override public final double normalizedDistance(Permutation p1, Permutation p2) { int m = max(p1.length()); diff --git a/src/org/cicirello/permutations/distance/AcyclicEdgeDistance.java b/src/org/cicirello/permutations/distance/AcyclicEdgeDistance.java index 0cc351c4..2c029fcb 100644 --- a/src/org/cicirello/permutations/distance/AcyclicEdgeDistance.java +++ b/src/org/cicirello/permutations/distance/AcyclicEdgeDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 Vincent A. Cicirello, . + * Copyright 2014-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -42,8 +42,7 @@ * S. Ronald, "Distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 1997, pp. 49–54.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public final class AcyclicEdgeDistance extends AbstractPermutationDistanceMeasurer { @@ -52,30 +51,25 @@ public final class AcyclicEdgeDistance extends AbstractPermutationDistanceMeasur */ public AcyclicEdgeDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } int countNonSharedEdges = 0; - int L1 = p1.length(); - int L2 = p2.length(); - if (L1==L2 && L1==0) return 0; - int[] successors2 = new int[L2]; - for (int i = 0; i < L2 - 1; i++) { + if (p1.length()==0) return 0; + int[] successors2 = new int[p2.length()]; + for (int i = 0; i < p2.length() - 1; i++) { successors2[p2.get(i)] = p2.get(i+1); } - successors2[p2.get(L2-1)] = -1; + successors2[p2.get(p2.length()-1)] = -1; - for (int i = 0; i < L1 - 1; i++) { + for (int i = 0; i < p1.length() - 1; i++) { if (p1.get(i+1) != successors2[p1.get(i)] && p1.get(i) != successors2[p1.get(i+1)]) countNonSharedEdges++; } return countNonSharedEdges; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 2) return 0; diff --git a/src/org/cicirello/permutations/distance/BlockInterchangeDistance.java b/src/org/cicirello/permutations/distance/BlockInterchangeDistance.java index 197d06ef..b3098ce5 100644 --- a/src/org/cicirello/permutations/distance/BlockInterchangeDistance.java +++ b/src/org/cicirello/permutations/distance/BlockInterchangeDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Vincent A. Cicirello, . + * Copyright 2019, 2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -40,8 +40,7 @@ *

Runtime: O(n), where n is the permutation length.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 7.26.19 - * @since 2.0 + * @version 1.28.2021 */ public class BlockInterchangeDistance extends AbstractPermutationDistanceMeasurer { @@ -50,11 +49,11 @@ public class BlockInterchangeDistance extends AbstractPermutationDistanceMeasure */ public BlockInterchangeDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } int[] inv2 = p2.getInverse(); int[] p = new int[inv2.length+2]; int[] inv = new int[p.length]; @@ -81,9 +80,6 @@ public int distance(Permutation p1, Permutation p2) { return (p1.length()+1-cycles)/2; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { return length >> 1; diff --git a/src/org/cicirello/permutations/distance/CyclicEdgeDistance.java b/src/org/cicirello/permutations/distance/CyclicEdgeDistance.java index c11150ed..8dc4ab33 100644 --- a/src/org/cicirello/permutations/distance/CyclicEdgeDistance.java +++ b/src/org/cicirello/permutations/distance/CyclicEdgeDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2019 Vincent A. Cicirello, . + * Copyright 2014-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -42,8 +42,7 @@ * S. Ronald, "Distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 1997, pp. 49–54.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public final class CyclicEdgeDistance extends AbstractPermutationDistanceMeasurer { @@ -52,30 +51,24 @@ public final class CyclicEdgeDistance extends AbstractPermutationDistanceMeasure */ public CyclicEdgeDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } int countNonSharedEdges = 0; - int L1 = p1.length(); - int L2 = p2.length(); - - int[] successors2 = new int[L2]; - for (int i = 0; i < L2; i++) { - successors2[p2.get(i)] = p2.get((i+1) % L2); + int[] successors2 = new int[p2.length()]; + for (int i = 0; i < successors2.length; i++) { + successors2[p2.get(i)] = p2.get((i+1) % successors2.length); } - for (int i = 0; i < L1; i++) { - if (p1.get((i+1) % L1) != successors2[p1.get(i)] && p1.get(i) != successors2[p1.get((i+1) % L1)]) countNonSharedEdges++; + for (int i = 0; i < successors2.length; i++) { + if (p1.get((i+1) % successors2.length) != successors2[p1.get(i)] && p1.get(i) != successors2[p1.get((i+1) % successors2.length)]) countNonSharedEdges++; } return countNonSharedEdges; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 3) return 0; diff --git a/src/org/cicirello/permutations/distance/CyclicIndependentDistance.java b/src/org/cicirello/permutations/distance/CyclicIndependentDistance.java index dab50a7f..32d0ad3f 100644 --- a/src/org/cicirello/permutations/distance/CyclicIndependentDistance.java +++ b/src/org/cicirello/permutations/distance/CyclicIndependentDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -32,8 +32,7 @@ * the constructor.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class CyclicIndependentDistance implements PermutationDistanceMeasurer { @@ -56,6 +55,7 @@ public CyclicIndependentDistance(PermutationDistanceMeasurer d) { * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public int distance(Permutation p1, Permutation p2) { @@ -70,7 +70,13 @@ public int distance(Permutation p1, Permutation p2) { } /** - * {@inheritDoc} + * Measures the distance between two permutations, with cyclic independence: + * distance = min_{i in [0,N)} distance(p1,rotate(p2,i)) + * + * @param p1 first permutation + * @param p2 second permutation + * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public final double distancef(Permutation p1, Permutation p2) { diff --git a/src/org/cicirello/permutations/distance/CyclicIndependentDistanceDouble.java b/src/org/cicirello/permutations/distance/CyclicIndependentDistanceDouble.java index 8afb9ddb..dfbd4e63 100644 --- a/src/org/cicirello/permutations/distance/CyclicIndependentDistanceDouble.java +++ b/src/org/cicirello/permutations/distance/CyclicIndependentDistanceDouble.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -32,8 +32,7 @@ * the constructor.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.5.10 - * @since 1.0 + * @version 1.28.2021 * */ public final class CyclicIndependentDistanceDouble implements PermutationDistanceMeasurerDouble { @@ -56,6 +55,7 @@ public CyclicIndependentDistanceDouble(PermutationDistanceMeasurerDouble d) { * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public double distancef(Permutation p1, Permutation p2) { diff --git a/src/org/cicirello/permutations/distance/CyclicRTypeDistance.java b/src/org/cicirello/permutations/distance/CyclicRTypeDistance.java index 9f373c68..58456fa8 100644 --- a/src/org/cicirello/permutations/distance/CyclicRTypeDistance.java +++ b/src/org/cicirello/permutations/distance/CyclicRTypeDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, 2014-2015, 2017-2019 Vincent A. Cicirello, . + * Copyright 2010, 2014-2015, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -44,8 +44,7 @@ * IEEE Transactions on Evolutionary Computation, 20(3):434-446, June 2016.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public final class CyclicRTypeDistance extends AbstractPermutationDistanceMeasurer { @@ -54,29 +53,23 @@ public final class CyclicRTypeDistance extends AbstractPermutationDistanceMeasur */ public CyclicRTypeDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } int countNonSharedEdges = 0; - int L1 = p1.length(); - int L2 = p2.length(); - - int[] successors2 = new int[L2]; - for (int i = 0; i < L2; i++) { - successors2[p2.get(i)] = p2.get((i+1) % L2); + int[] successors2 = new int[p2.length()]; + for (int i = 0; i < successors2.length; i++) { + successors2[p2.get(i)] = p2.get((i+1) % successors2.length); } - for (int i = 0; i < L1; i++) { - if (p1.get((i+1) % L1) != successors2[p1.get(i)]) countNonSharedEdges++; + for (int i = 0; i < successors2.length; i++) { + if (p1.get((i+1) % successors2.length) != successors2[p1.get(i)]) countNonSharedEdges++; } return countNonSharedEdges; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 2) return 0; diff --git a/src/org/cicirello/permutations/distance/CyclicReversalIndependentDistance.java b/src/org/cicirello/permutations/distance/CyclicReversalIndependentDistance.java index 6a880893..d5ed52ca 100644 --- a/src/org/cicirello/permutations/distance/CyclicReversalIndependentDistance.java +++ b/src/org/cicirello/permutations/distance/CyclicReversalIndependentDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -33,8 +33,7 @@ * the constructor.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class CyclicReversalIndependentDistance implements PermutationDistanceMeasurer { @@ -57,6 +56,7 @@ public CyclicReversalIndependentDistance(PermutationDistanceMeasurer d) { * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public int distance(Permutation p1, Permutation p2) { @@ -85,7 +85,13 @@ public int distance(Permutation p1, Permutation p2) { } /** - * {@inheritDoc} + * Measures the distance between two permutations, with cyclic and reversal independence: + * distance = min_{i in [0,N)} { distance(p1,rotate(p2,i)), distance(p1,rotate(reverse(p2),i)) } + * + * @param p1 first permutation + * @param p2 second permutation + * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public final double distancef(Permutation p1, Permutation p2) { diff --git a/src/org/cicirello/permutations/distance/CyclicReversalIndependentDistanceDouble.java b/src/org/cicirello/permutations/distance/CyclicReversalIndependentDistanceDouble.java index e7e5934b..49d1f788 100644 --- a/src/org/cicirello/permutations/distance/CyclicReversalIndependentDistanceDouble.java +++ b/src/org/cicirello/permutations/distance/CyclicReversalIndependentDistanceDouble.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -33,8 +33,7 @@ * the constructor.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.5.10 - * @since 1.0 + * @version 1.28.2021 * */ public final class CyclicReversalIndependentDistanceDouble implements PermutationDistanceMeasurerDouble { @@ -57,6 +56,7 @@ public CyclicReversalIndependentDistanceDouble(PermutationDistanceMeasurerDouble * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public double distancef(Permutation p1, Permutation p2) { diff --git a/src/org/cicirello/permutations/distance/DeviationDistance.java b/src/org/cicirello/permutations/distance/DeviationDistance.java index a859ff25..9ed0edaf 100644 --- a/src/org/cicirello/permutations/distance/DeviationDistance.java +++ b/src/org/cicirello/permutations/distance/DeviationDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2008, 2010, 2014, 2017-2019 Vincent A. Cicirello, . + * Copyright 2008, 2010, 2014, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -42,8 +42,7 @@ * S. Ronald, "More distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 1998, pp. 558–563.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class DeviationDistance extends AbstractPermutationDistanceMeasurer { @@ -53,25 +52,21 @@ public final class DeviationDistance extends AbstractPermutationDistanceMeasurer */ public DeviationDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } + int distancePoints = 0; - int L1 = p1.length(); - int[] invP2 = p2.getInverse(); - for (int i = 0; i < L1; i++) { + for (int i = 0; i < invP2.length; i++) { distancePoints += Math.abs(invP2[p1.get(i)]-i); } return distancePoints; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java index 13011056..c63d3d6c 100644 --- a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java +++ b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java @@ -1,5 +1,5 @@ /* - * Copyright 2014, 2017-2019 Vincent A. Cicirello, . + * Copyright 2014, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -48,8 +48,7 @@ * Proc. IEEE CEC. IEEE Press, 1998, pp. 558–563.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class DeviationDistanceNormalized implements PermutationDistanceMeasurerDouble, NormalizedPermutationDistanceMeasurerDouble { @@ -63,28 +62,18 @@ public DeviationDistanceNormalized() { devDistance = new DeviationDistance(); } - /** - * {@inheritDoc} - */ @Override public double distancef(Permutation p1, Permutation p2) { if (p1.length() <= 1) return 0; return devDistance.distancef(p1,p2) / (p1.length() - 1); } - /** - * {@inheritDoc} - */ @Override public double maxf(int length) { if (length <= 1) return 0; return (length * length - (length & 1)) / (2.0 * (length-1)); } - - /** - * {@inheritDoc} - */ @Override public double normalizedDistance(Permutation p1, Permutation p2) { double m = maxf(p1.length()); diff --git a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java index 1c7ec9aa..5d16ea83 100644 --- a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java +++ b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Vincent A. Cicirello, . + * Copyright 2019-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -62,8 +62,7 @@ * management," in Proc. of MIC2005, 2005.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.2.3 + * @version 1.28.2021 * */ public final class DeviationDistanceNormalized2005 implements PermutationDistanceMeasurerDouble, NormalizedPermutationDistanceMeasurerDouble { @@ -77,27 +76,18 @@ public DeviationDistanceNormalized2005() { devDistance = new DeviationDistance(); } - /** - * {@inheritDoc} - */ @Override public double distancef(Permutation p1, Permutation p2) { if (p1.length() <= 1) return 0; return devDistance.distancef(p1,p2) * 2.0 / (p1.length() * p1.length() - (p1.length() & 1)); } - /** - * {@inheritDoc} - */ @Override public double maxf(int length) { if (length <= 1) return 0; return 1.0; } - /** - * {@inheritDoc} - */ @Override public double normalizedDistance(Permutation p1, Permutation p2) { return distancef(p1,p2); diff --git a/src/org/cicirello/permutations/distance/EditDistance.java b/src/org/cicirello/permutations/distance/EditDistance.java index 61d6aba2..5a745819 100644 --- a/src/org/cicirello/permutations/distance/EditDistance.java +++ b/src/org/cicirello/permutations/distance/EditDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, 2017-2019 Vincent A. Cicirello, . + * Copyright 2010, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -53,8 +53,7 @@ * in Proceedings of the 26th FLAIRS Conference. AAAI Press, May 2013, pp. 46–51.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public final class EditDistance implements PermutationDistanceMeasurerDouble { @@ -86,7 +85,11 @@ public EditDistance() { } /** - * {@inheritDoc} + * Measures the distance between two permutations. + * + * @param p1 first permutation + * @param p2 second permutation + * @return distance between p1 and p2 */ @Override public double distancef(Permutation p1, Permutation p2) { diff --git a/src/org/cicirello/permutations/distance/ExactMatchDistance.java b/src/org/cicirello/permutations/distance/ExactMatchDistance.java index 52f9144b..c42eeaed 100644 --- a/src/org/cicirello/permutations/distance/ExactMatchDistance.java +++ b/src/org/cicirello/permutations/distance/ExactMatchDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2008, 2010, 2017-2019 Vincent A. Cicirello, . + * Copyright 2008, 2010, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -33,8 +33,7 @@ * S. Ronald, "More distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 1998, pp. 558–563.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public final class ExactMatchDistance extends AbstractPermutationDistanceMeasurer { @@ -43,14 +42,13 @@ public final class ExactMatchDistance extends AbstractPermutationDistanceMeasure */ public ExactMatchDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } int misMatchPoints = 0; - int L = p1.length(); - for (int i = 0; i < L; i++) { + for (int i = 0; i < p1.length(); i++) { if (p1.get(i) != p2.get(i)) { misMatchPoints++; } @@ -58,9 +56,6 @@ public int distance(Permutation p1, Permutation p2) { return misMatchPoints; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/src/org/cicirello/permutations/distance/InterchangeDistance.java b/src/org/cicirello/permutations/distance/InterchangeDistance.java index d9c5020e..0499048a 100644 --- a/src/org/cicirello/permutations/distance/InterchangeDistance.java +++ b/src/org/cicirello/permutations/distance/InterchangeDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, 2014, 2017-2019 Vincent A. Cicirello, . + * Copyright 2010, 2014, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -40,8 +40,7 @@ * IEEE Transactions on Evolutionary Computation, 20(3):434-446, June 2016.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public final class InterchangeDistance extends AbstractPermutationDistanceMeasurer { @@ -50,17 +49,15 @@ public final class InterchangeDistance extends AbstractPermutationDistanceMeasur */ public InterchangeDistance() {} - /** - * {@inheritDoc} - */ - @Override - public int distance(Permutation p1, Permutation p2) - { + @Override + public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } int numSwaps = 0; int length = p1.length(); boolean[] used = new boolean[length]; - for (int k = 0; k < length; k++) - { + for (int k = 0; k < length; k++) { if (p1.get(k) == p2.get(k)) used[p1.get(k)] = true; } int i = 0; @@ -91,9 +88,6 @@ public int distance(Permutation p1, Permutation p2) return numSwaps; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/src/org/cicirello/permutations/distance/KendallTauDistance.java b/src/org/cicirello/permutations/distance/KendallTauDistance.java index 012df9da..9fe2f322 100644 --- a/src/org/cicirello/permutations/distance/KendallTauDistance.java +++ b/src/org/cicirello/permutations/distance/KendallTauDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2014, 2015, 2017-2019 Vincent A. Cicirello, . + * Copyright 2014, 2015, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -48,8 +48,7 @@ * M. G. Kendall, "A new measure of rank correlation," Biometrika, vol. 30, no. 1/2, pp. 81–93, June 1938.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class KendallTauDistance extends AbstractPermutationDistanceMeasurer { @@ -59,28 +58,23 @@ public final class KendallTauDistance extends AbstractPermutationDistanceMeasure */ public KendallTauDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { - - int n = p2.length(); + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } // use inverse of p1 as a relabeling int[] invP1 = p1.getInverse(); // relabel array copy of p2 - int[] arrayP2 = new int[n]; - for (int i = 0; i < n; i++) { + int[] arrayP2 = new int[invP1.length]; + for (int i = 0; i < arrayP2.length; i++) { arrayP2[i] = invP1[p2.get(i)]; } return countInversions(arrayP2); } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/src/org/cicirello/permutations/distance/LeeDistance.java b/src/org/cicirello/permutations/distance/LeeDistance.java index 7a5168eb..54c2b57a 100644 --- a/src/org/cicirello/permutations/distance/LeeDistance.java +++ b/src/org/cicirello/permutations/distance/LeeDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2014, 2015, 2017-2019 Vincent A. Cicirello, . + * Copyright 2014, 2015, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -43,8 +43,7 @@ * C. Lee, "Some properties of nonbinary error-correcting codes," in IRE Transactions on Information Theory, vol. 4, no. 2, pp. 77-82, June 1958.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class LeeDistance extends AbstractPermutationDistanceMeasurer { @@ -54,28 +53,24 @@ public final class LeeDistance extends AbstractPermutationDistanceMeasurer { */ public LeeDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { - int L1 = p1.length(); - if (L1 <= 1) return 0; + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } + if (p1.length() <= 1) return 0; int distancePoints = 0; int[] invP1 = p1.getInverse(); int[] invP2 = p2.getInverse(); - for (int i = 0; i < L1; i++) { + for (int i = 0; i < invP1.length; i++) { int dev = Math.abs(invP1[i]-invP2[i]); - distancePoints += Math.min(dev, L1 - dev); + distancePoints += Math.min(dev, invP1.length - dev); } return distancePoints; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/src/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurer.java b/src/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurer.java index 4ad5a3d9..0fd6aba2 100644 --- a/src/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurer.java +++ b/src/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Vincent A. Cicirello, . + * Copyright 2019-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -27,8 +27,7 @@ * normalizing the distance to the interval [0,1], but where the base distance is an integer value. * * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.2.5 + * @version 1.28.2021 */ public interface NormalizedPermutationDistanceMeasurer extends NormalizedPermutationDistanceMeasurerDouble { @@ -38,7 +37,6 @@ public interface NormalizedPermutationDistanceMeasurer extends NormalizedPermuta * * @param length Permutation length. * @return the maximum distance between a pair of permutations of the specified length. - * @since 1.2.5 */ int max(int length); } \ No newline at end of file diff --git a/src/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurerDouble.java b/src/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurerDouble.java index c96dcb63..ce753e68 100644 --- a/src/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurerDouble.java +++ b/src/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurerDouble.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Vincent A. Cicirello, . + * Copyright 2019-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -27,8 +27,7 @@ * normalizing the distance to the interval [0,1]. * * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.2.5 + * @version 1.28.2021 */ public interface NormalizedPermutationDistanceMeasurerDouble { @@ -38,7 +37,7 @@ public interface NormalizedPermutationDistanceMeasurerDouble { * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 normalized to the interval [0.0, 1.0] - * @since 1.2.5 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ double normalizedDistance(Permutation p1, Permutation p2); @@ -48,7 +47,6 @@ public interface NormalizedPermutationDistanceMeasurerDouble { * * @param length Permutation length. * @return the maximum distance between a pair of permutations of the specified length. - * @since 1.2.5 */ double maxf(int length); } \ No newline at end of file diff --git a/src/org/cicirello/permutations/distance/PermutationDistanceMeasurer.java b/src/org/cicirello/permutations/distance/PermutationDistanceMeasurer.java index ed388c55..59d2ddcc 100644 --- a/src/org/cicirello/permutations/distance/PermutationDistanceMeasurer.java +++ b/src/org/cicirello/permutations/distance/PermutationDistanceMeasurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, 2017-2019 Vincent A. Cicirello, . + * Copyright 2010, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -26,8 +26,7 @@ * Implement this interface, PermutationDistanceMeasurer, to define a distance metric for permutations. * * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public interface PermutationDistanceMeasurer extends PermutationDistanceMeasurerDouble { @@ -37,6 +36,7 @@ public interface PermutationDistanceMeasurer extends PermutationDistanceMeasurer * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ int distance(Permutation p1, Permutation p2); } diff --git a/src/org/cicirello/permutations/distance/PermutationDistanceMeasurerDouble.java b/src/org/cicirello/permutations/distance/PermutationDistanceMeasurerDouble.java index a8a23d09..3915efa2 100644 --- a/src/org/cicirello/permutations/distance/PermutationDistanceMeasurerDouble.java +++ b/src/org/cicirello/permutations/distance/PermutationDistanceMeasurerDouble.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, 2017-2019 Vincent A. Cicirello, . + * Copyright 2010, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -27,17 +27,16 @@ * where the distance is a floating-point value. * * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.5.10 - * @since 1.0 + * @version 1.28.2021 */ -public interface PermutationDistanceMeasurerDouble -{ +public interface PermutationDistanceMeasurerDouble { /** * Measures the distance between two permutations * * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ double distancef(Permutation p1, Permutation p2); diff --git a/src/org/cicirello/permutations/distance/RTypeDistance.java b/src/org/cicirello/permutations/distance/RTypeDistance.java index e1529779..4fcab39c 100644 --- a/src/org/cicirello/permutations/distance/RTypeDistance.java +++ b/src/org/cicirello/permutations/distance/RTypeDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2010, 2014, 2017-2019 Vincent A. Cicirello, . + * Copyright 2010, 2014, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -44,8 +44,7 @@ * INFORMS Journal on Computing, vol. 17, no. 1, pp. 111–122, 2005.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public final class RTypeDistance extends AbstractPermutationDistanceMeasurer { @@ -54,30 +53,25 @@ public final class RTypeDistance extends AbstractPermutationDistanceMeasurer { */ public RTypeDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } int countNonSharedEdges = 0; - int L1 = p1.length(); - int L2 = p2.length(); - if (L1==L2 && L1==0) return 0; - int[] successors2 = new int[L2]; - for (int i = 0; i < L2 - 1; i++) { + if (p2.length()==0) return 0; + int[] successors2 = new int[p2.length()]; + for (int i = 0; i < successors2.length - 1; i++) { successors2[p2.get(i)] = p2.get(i+1); } - successors2[p2.get(L2-1)] = -1; + successors2[p2.get(successors2.length-1)] = -1; - for (int i = 0; i < L1 - 1; i++) { + for (int i = 0; i < successors2.length - 1; i++) { if (p1.get(i+1) != successors2[p1.get(i)]) countNonSharedEdges++; } return countNonSharedEdges; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/src/org/cicirello/permutations/distance/ReinsertionDistance.java b/src/org/cicirello/permutations/distance/ReinsertionDistance.java index 6ce546f0..27fc2d0c 100644 --- a/src/org/cicirello/permutations/distance/ReinsertionDistance.java +++ b/src/org/cicirello/permutations/distance/ReinsertionDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2015, 2017-2019 Vincent A. Cicirello, . + * Copyright 2015, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -57,8 +57,7 @@ * Communications of the ACM, 20(5):350-353, May, 1977.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class ReinsertionDistance extends AbstractPermutationDistanceMeasurer { @@ -68,17 +67,14 @@ public final class ReinsertionDistance extends AbstractPermutationDistanceMeasur */ public ReinsertionDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } return p1.length() - lcs(p1,p2); } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; @@ -87,7 +83,7 @@ public int max(int length) { // This version runs in O(n lg n) private int lcs(Permutation p1, Permutation p2) { - int n = p1.length(); + final int n = p1.length(); int[] inv = p2.getInverse(); int[] match = new int[n]; int[] thresh = new int[n+1]; @@ -110,7 +106,7 @@ private int lcs(Permutation p1, Permutation p2) { private int binSearch(int[] array, int value, int low, int high) { if (high == low) return low; - int mid = (high+low) >> 1; + final int mid = (high+low) >> 1; if (value <= array[mid] && value > array[mid-1]) { return mid; } else if (value > array[mid]) { diff --git a/src/org/cicirello/permutations/distance/ReversalDistance.java b/src/org/cicirello/permutations/distance/ReversalDistance.java index de078303..bcb1c6c6 100644 --- a/src/org/cicirello/permutations/distance/ReversalDistance.java +++ b/src/org/cicirello/permutations/distance/ReversalDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Vincent A. Cicirello, . + * Copyright 2015-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -47,8 +47,7 @@ *

We have not used this for N > 10. Warning: time to construct distance measure increases factorially.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ -* @version 1.19.6.12 -* @since 1.0 +* @version 1.28.2021 */ public final class ReversalDistance extends AbstractPermutationDistanceMeasurer { @@ -107,26 +106,17 @@ public ReversalDistance(int n) { } } - - - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { - int n = p1.length(); - if (p2.length() != n || n != PERM_LENGTH) throw new IllegalArgumentException("This distance measurer is configured for permutations of length " + PERM_LENGTH + " only."); + if (p2.length() != p1.length() || p1.length() != PERM_LENGTH) throw new IllegalArgumentException("This distance measurer is configured for permutations of length " + PERM_LENGTH + " only."); int[] inv1 = p1.getInverse(); - int[] r2 = new int[n]; - for (int i = 0; i < n; i++) { + int[] r2 = new int[inv1.length]; + for (int i = 0; i < inv1.length; i++) { r2[i] = inv1[p2.get(i)]; } return dist[(new Permutation(r2)).toInteger()]; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/src/org/cicirello/permutations/distance/ReversalIndependentDistance.java b/src/org/cicirello/permutations/distance/ReversalIndependentDistance.java index aecfbb99..3ba088db 100644 --- a/src/org/cicirello/permutations/distance/ReversalIndependentDistance.java +++ b/src/org/cicirello/permutations/distance/ReversalIndependentDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -32,8 +32,7 @@ * to the constructor.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class ReversalIndependentDistance implements PermutationDistanceMeasurer { @@ -56,6 +55,7 @@ public ReversalIndependentDistance(PermutationDistanceMeasurer d) { * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public int distance(Permutation p1, Permutation p2) { @@ -69,7 +69,13 @@ public int distance(Permutation p1, Permutation p2) { } /** - * {@inheritDoc} + * Measures the distance between two permutations, with reversal independence: + * distance = min { distance(p1,p2), distance(p1,reverse(p2)) } + * + * @param p1 first permutation + * @param p2 second permutation + * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public final double distancef(Permutation p1, Permutation p2) { diff --git a/src/org/cicirello/permutations/distance/ReversalIndependentDistanceDouble.java b/src/org/cicirello/permutations/distance/ReversalIndependentDistanceDouble.java index 04fe9a1b..3226db69 100644 --- a/src/org/cicirello/permutations/distance/ReversalIndependentDistanceDouble.java +++ b/src/org/cicirello/permutations/distance/ReversalIndependentDistanceDouble.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -32,8 +32,7 @@ * to the constructor.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.5.10 - * @since 1.0 + * @version 1.28.2021 * */ public final class ReversalIndependentDistanceDouble implements PermutationDistanceMeasurerDouble { @@ -56,6 +55,7 @@ public ReversalIndependentDistanceDouble(PermutationDistanceMeasurerDouble d) { * @param p1 first permutation * @param p2 second permutation * @return distance between p1 and p2 + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). */ @Override public double distancef(Permutation p1, Permutation p2) { diff --git a/src/org/cicirello/permutations/distance/ScrambleDistance.java b/src/org/cicirello/permutations/distance/ScrambleDistance.java index 368295e0..ce745324 100644 --- a/src/org/cicirello/permutations/distance/ScrambleDistance.java +++ b/src/org/cicirello/permutations/distance/ScrambleDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Vincent A. Cicirello, . + * Copyright 2016-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -32,8 +32,7 @@ *

Runtime: O(n), where n is the permutation length.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 */ public final class ScrambleDistance extends AbstractPermutationDistanceMeasurer { @@ -42,18 +41,12 @@ public final class ScrambleDistance extends AbstractPermutationDistanceMeasurer */ public ScrambleDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.equals(p2)) return 0; else return 1; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/src/org/cicirello/permutations/distance/SquaredDeviationDistance.java b/src/org/cicirello/permutations/distance/SquaredDeviationDistance.java index 9b6bbdfd..4ceefb7e 100644 --- a/src/org/cicirello/permutations/distance/SquaredDeviationDistance.java +++ b/src/org/cicirello/permutations/distance/SquaredDeviationDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2014, 2015, 2017-2019 Vincent A. Cicirello, . + * Copyright 2014, 2015, 2017-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -44,8 +44,7 @@ * The 6th Metaheuristics International Conference, August, 2005.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.12 - * @since 1.0 + * @version 1.28.2021 * */ public final class SquaredDeviationDistance extends AbstractPermutationDistanceMeasurer { @@ -55,26 +54,22 @@ public final class SquaredDeviationDistance extends AbstractPermutationDistanceM */ public SquaredDeviationDistance() {} - /** - * {@inheritDoc} - */ @Override public int distance(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } int distancePoints = 0; - int L1 = p1.length(); int[] invP2 = p2.getInverse(); - for (int i = 0; i < L1; i++) { + for (int i = 0; i < invP2.length; i++) { int dev = invP2[p1.get(i)]-i; distancePoints += (dev*dev); } return distancePoints; } - /** - * {@inheritDoc} - */ @Override public int max(int length) { if (length <= 1) return 0; diff --git a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java index e1d47659..2f7a1527 100644 --- a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java +++ b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * From 8f3da895642883eeec9848cdf8e071691c5e5bec Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Thu, 28 Jan 2021 17:04:02 -0500 Subject: [PATCH 06/22] Validation checking for same length permutations --- .../permutations/distance/DeviationDistanceNormalized.java | 3 +++ .../permutations/distance/DeviationDistanceNormalized2005.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java index c63d3d6c..12d21164 100644 --- a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java +++ b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java @@ -64,6 +64,9 @@ public DeviationDistanceNormalized() { @Override public double distancef(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } if (p1.length() <= 1) return 0; return devDistance.distancef(p1,p2) / (p1.length() - 1); } diff --git a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java index 5d16ea83..5a04b2d8 100644 --- a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java +++ b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java @@ -78,6 +78,9 @@ public DeviationDistanceNormalized2005() { @Override public double distancef(Permutation p1, Permutation p2) { + if (p1.length() != p2.length()) { + throw new IllegalArgumentException("Permutations must be the same length"); + } if (p1.length() <= 1) return 0; return devDistance.distancef(p1,p2) * 2.0 / (p1.length() * p1.length() - (p1.length() & 1)); } From 804dc10d0f232ccc667c2cbe8f8a3fbf9cdcc201 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Thu, 28 Jan 2021 17:04:41 -0500 Subject: [PATCH 07/22] Improved test coverage --- .../distance/PermutationDistanceTests.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java index 2f7a1527..7c938d73 100644 --- a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java +++ b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java @@ -83,6 +83,11 @@ public void testBlockInterchangeDistance() { assertEquals("1 block interchange lengths 2,4", 1, d.distance(p, p24)); assertEquals("1 block interchange lengths 2,3", 1, d.distance(p23, p)); assertEquals("1 block interchange lengths 2,4", 1, d.distance(p24, p)); + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -102,6 +107,11 @@ public void testAcyclicEdgeDistance() { assertEquals("intermediate distance", 2, d.distance(p1, p3)); p3.reverse(); assertEquals("reversal invariant intermediate distance", 2, d.distance(p1, p3)); + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -132,6 +142,11 @@ public void testCyclicEdgeDistance() { p3.rotate(1); assertEquals("rotational invariant intermediate distance", 3, d.distance(p1, p3)); } + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -158,6 +173,11 @@ public void testCyclicRTypeDistance() { Permutation r = new Permutation(p1); r.reverse(); assertEquals("reverse is maximal distance", 6, d.distance(p1, r)); + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -175,6 +195,11 @@ public void testRTypeDistance() { Permutation r = new Permutation(p1); r.reverse(); assertEquals("reverse is maximal distance", 5, d.distance(p1, r)); + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -191,6 +216,11 @@ public void testDeviationDistance() { assertEquals("deviation distance", expected, d.distance(p, copy)); } } + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -208,6 +238,11 @@ public void testDeviationDistanceNormalized() { assertEquals("deviation distance", expectedD, d.distancef(p, copy), EPSILON); } } + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distancef(new Permutation(1), new Permutation(2)) + ); } @Test @@ -232,6 +267,11 @@ public void testDeviationDistanceNormalized2005() { // Reverse of permutation should be distance 1.0 from original. assertEquals("deviation distance", 1, d.distancef(p, reversed), EPSILON); } + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distancef(new Permutation(1), new Permutation(2)) + ); } @Test @@ -248,6 +288,11 @@ public void testSquaredDeviationDistance() { assertEquals("squared deviation distance", expected, d.distance(p, copy)); } } + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -264,6 +309,11 @@ public void testLeeDistance() { assertEquals("Lee distance", expected, d.distance(p, copy)); } } + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -281,6 +331,11 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(p1,p2)); assertEquals("end points differ", 2, d.distance(p1,p3)); assertEquals("differ in interior positions", 2, d.distance(p1,p4)); + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -302,6 +357,11 @@ public void testInterchangeDistance() { assertEquals("end points switched", 1, d.distance(p1,p3)); assertEquals("one swap different", 1, d.distance(p1,p4)); assertEquals("two permutation cycles", 4, d.distance(p1,p5)); + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test @@ -324,6 +384,11 @@ public void testKendallTauDistance() { for (Permutation q : p) { assertEquals("checking consistence with naive implementation", naiveKendalTau(p,q), d.distance(p,q)); } + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } private int naiveKendalTau(Permutation p1, Permutation p2) { @@ -373,6 +438,11 @@ public void testReinsertionDistance() { // Should correspond if they are both correct. assertEquals("equiv of edit with 0.5 cost removes and inserts", edit.distancef(p,q), d.distancef(p,q), EPSILON); } + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new Permutation(1), new Permutation(2)) + ); } @Test From ea20d32ff1964d388998e27a960b776e9313c191 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Thu, 28 Jan 2021 17:10:11 -0500 Subject: [PATCH 08/22] improved test coverage --- .../permutations/distance/PermutationDistanceTests.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java index 7c938d73..6451b723 100644 --- a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java +++ b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java @@ -487,6 +487,12 @@ public void testEditDistance() { assertEquals("equiv of 2.25 reinsertion", 2.25*reinsert.distancef(p1,p2), d.distancef(p1,p2), EPSILON); } } + + // Different length case + d = new EditDistance(1.0, 9.0, 9.0); + int[] first = { 0, 1, 2 }; + int[] second = { 0, 1, 2, 3 }; + assertEquals(1.0, d.distancef(new Permutation(first), new Permutation(second)), EPSILON); } From 398895353f031e1b201aa403555ff81a6fa5f7e5 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 29 Jan 2021 13:36:21 -0500 Subject: [PATCH 09/22] Bug fix: ReversalDistance.max --- CHANGELOG.md | 1 + .../distance/ReversalDistance.java | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90f0a3ab..cb69905a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed * Bug in Permutation.toString which was inserting an extra space at end. * Added validation checking for all permutation distance measures validating same length permutations (except for EditDistance which can handle that case). +* Bug in ReversalDistance.max in case when permutation length is 2, and also added missing parameter validation. ### CI/CD * Migrated build process from Ant to Maven, including GitHub workflows. diff --git a/src/org/cicirello/permutations/distance/ReversalDistance.java b/src/org/cicirello/permutations/distance/ReversalDistance.java index bcb1c6c6..f79b135b 100644 --- a/src/org/cicirello/permutations/distance/ReversalDistance.java +++ b/src/org/cicirello/permutations/distance/ReversalDistance.java @@ -47,12 +47,12 @@ *

We have not used this for N > 10. Warning: time to construct distance measure increases factorially.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ -* @version 1.28.2021 +* @version 1.29.2021 */ public final class ReversalDistance extends AbstractPermutationDistanceMeasurer { private byte[] dist; - private int PERM_LENGTH; + private final int PERM_LENGTH; private int maxd; /** @@ -72,6 +72,7 @@ public ReversalDistance(int n) { if (n > 12 || n < 0) throw new IllegalArgumentException("Requires 0 <= n <= 12."); PERM_LENGTH = n; int fact = 1; + maxd = 0; for (int i = 2; i <= n; i++) fact *= i; dist = new byte[fact]; Permutation p = new Permutation(n,0); @@ -81,6 +82,7 @@ public ReversalDistance(int n) { int v = p.toInteger(); p.reverse(i,j); dist[v] = 1; + maxd = 1; } } int visited = n * (n-1) / 2 + 1; @@ -106,6 +108,14 @@ public ReversalDistance(int n) { } } + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if length of the permutations + * is not equal to the + * the permutation length for which this was configured at time + * of construction. + */ @Override public int distance(Permutation p1, Permutation p2) { if (p2.length() != p1.length() || p1.length() != PERM_LENGTH) throw new IllegalArgumentException("This distance measurer is configured for permutations of length " + PERM_LENGTH + " only."); @@ -117,9 +127,18 @@ public int distance(Permutation p1, Permutation p2) { return dist[(new Permutation(r2)).toInteger()]; } + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if length is not equal to the + * the permutation length for which this was configured at time + * of construction. + */ @Override public int max(int length) { - if (length <= 1) return 0; + if (PERM_LENGTH != length) { + throw new IllegalArgumentException("This distance measurer was not configured for length: " + length); + } return maxd; } From a766007ef9875f0e2e771ef08010f54d269db3b4 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 29 Jan 2021 13:48:29 -0500 Subject: [PATCH 10/22] doc edits --- .../distance/AbstractPermutationDistanceMeasurer.java | 10 ++++++++++ .../permutations/distance/AcyclicEdgeDistance.java | 5 +++++ .../distance/BlockInterchangeDistance.java | 5 +++++ .../permutations/distance/CyclicEdgeDistance.java | 5 +++++ .../permutations/distance/CyclicRTypeDistance.java | 5 +++++ .../permutations/distance/DeviationDistance.java | 5 +++++ .../distance/DeviationDistanceNormalized.java | 10 ++++++++++ .../distance/DeviationDistanceNormalized2005.java | 10 ++++++++++ .../permutations/distance/ExactMatchDistance.java | 5 +++++ .../permutations/distance/InterchangeDistance.java | 5 +++++ .../permutations/distance/KendallTauDistance.java | 5 +++++ .../cicirello/permutations/distance/LeeDistance.java | 5 +++++ .../cicirello/permutations/distance/RTypeDistance.java | 5 +++++ .../permutations/distance/ReinsertionDistance.java | 5 +++++ .../permutations/distance/ReversalDistance.java | 1 + .../distance/SquaredDeviationDistance.java | 5 +++++ 16 files changed, 91 insertions(+) diff --git a/src/org/cicirello/permutations/distance/AbstractPermutationDistanceMeasurer.java b/src/org/cicirello/permutations/distance/AbstractPermutationDistanceMeasurer.java index 139ceebf..4eb0a80c 100644 --- a/src/org/cicirello/permutations/distance/AbstractPermutationDistanceMeasurer.java +++ b/src/org/cicirello/permutations/distance/AbstractPermutationDistanceMeasurer.java @@ -32,6 +32,11 @@ */ abstract class AbstractPermutationDistanceMeasurer implements PermutationDistanceMeasurer, NormalizedPermutationDistanceMeasurer { + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public final double distancef(Permutation p1, Permutation p2) { return distance(p1,p2); @@ -42,6 +47,11 @@ public final double maxf(int length) { return max(length); } + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public final double normalizedDistance(Permutation p1, Permutation p2) { int m = max(p1.length()); diff --git a/src/org/cicirello/permutations/distance/AcyclicEdgeDistance.java b/src/org/cicirello/permutations/distance/AcyclicEdgeDistance.java index 2c029fcb..3655b190 100644 --- a/src/org/cicirello/permutations/distance/AcyclicEdgeDistance.java +++ b/src/org/cicirello/permutations/distance/AcyclicEdgeDistance.java @@ -51,6 +51,11 @@ public final class AcyclicEdgeDistance extends AbstractPermutationDistanceMeasur */ public AcyclicEdgeDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/BlockInterchangeDistance.java b/src/org/cicirello/permutations/distance/BlockInterchangeDistance.java index b3098ce5..6c9881a2 100644 --- a/src/org/cicirello/permutations/distance/BlockInterchangeDistance.java +++ b/src/org/cicirello/permutations/distance/BlockInterchangeDistance.java @@ -49,6 +49,11 @@ public class BlockInterchangeDistance extends AbstractPermutationDistanceMeasure */ public BlockInterchangeDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/CyclicEdgeDistance.java b/src/org/cicirello/permutations/distance/CyclicEdgeDistance.java index 8dc4ab33..01d2bb04 100644 --- a/src/org/cicirello/permutations/distance/CyclicEdgeDistance.java +++ b/src/org/cicirello/permutations/distance/CyclicEdgeDistance.java @@ -51,6 +51,11 @@ public final class CyclicEdgeDistance extends AbstractPermutationDistanceMeasure */ public CyclicEdgeDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/CyclicRTypeDistance.java b/src/org/cicirello/permutations/distance/CyclicRTypeDistance.java index 58456fa8..639403df 100644 --- a/src/org/cicirello/permutations/distance/CyclicRTypeDistance.java +++ b/src/org/cicirello/permutations/distance/CyclicRTypeDistance.java @@ -53,6 +53,11 @@ public final class CyclicRTypeDistance extends AbstractPermutationDistanceMeasur */ public CyclicRTypeDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/DeviationDistance.java b/src/org/cicirello/permutations/distance/DeviationDistance.java index 9ed0edaf..5dfca656 100644 --- a/src/org/cicirello/permutations/distance/DeviationDistance.java +++ b/src/org/cicirello/permutations/distance/DeviationDistance.java @@ -52,6 +52,11 @@ public final class DeviationDistance extends AbstractPermutationDistanceMeasurer */ public DeviationDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java index 12d21164..f399f74e 100644 --- a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java +++ b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized.java @@ -62,6 +62,11 @@ public DeviationDistanceNormalized() { devDistance = new DeviationDistance(); } + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public double distancef(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { @@ -77,6 +82,11 @@ public double maxf(int length) { return (length * length - (length & 1)) / (2.0 * (length-1)); } + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public double normalizedDistance(Permutation p1, Permutation p2) { double m = maxf(p1.length()); diff --git a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java index 5a04b2d8..37248f07 100644 --- a/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java +++ b/src/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java @@ -76,6 +76,11 @@ public DeviationDistanceNormalized2005() { devDistance = new DeviationDistance(); } + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public double distancef(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { @@ -91,6 +96,11 @@ public double maxf(int length) { return 1.0; } + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public double normalizedDistance(Permutation p1, Permutation p2) { return distancef(p1,p2); diff --git a/src/org/cicirello/permutations/distance/ExactMatchDistance.java b/src/org/cicirello/permutations/distance/ExactMatchDistance.java index c42eeaed..2cf229a1 100644 --- a/src/org/cicirello/permutations/distance/ExactMatchDistance.java +++ b/src/org/cicirello/permutations/distance/ExactMatchDistance.java @@ -42,6 +42,11 @@ public final class ExactMatchDistance extends AbstractPermutationDistanceMeasure */ public ExactMatchDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/InterchangeDistance.java b/src/org/cicirello/permutations/distance/InterchangeDistance.java index 0499048a..ff7aad60 100644 --- a/src/org/cicirello/permutations/distance/InterchangeDistance.java +++ b/src/org/cicirello/permutations/distance/InterchangeDistance.java @@ -49,6 +49,11 @@ public final class InterchangeDistance extends AbstractPermutationDistanceMeasur */ public InterchangeDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/KendallTauDistance.java b/src/org/cicirello/permutations/distance/KendallTauDistance.java index 9fe2f322..7b4e6616 100644 --- a/src/org/cicirello/permutations/distance/KendallTauDistance.java +++ b/src/org/cicirello/permutations/distance/KendallTauDistance.java @@ -58,6 +58,11 @@ public final class KendallTauDistance extends AbstractPermutationDistanceMeasure */ public KendallTauDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/LeeDistance.java b/src/org/cicirello/permutations/distance/LeeDistance.java index 54c2b57a..b079bef4 100644 --- a/src/org/cicirello/permutations/distance/LeeDistance.java +++ b/src/org/cicirello/permutations/distance/LeeDistance.java @@ -53,6 +53,11 @@ public final class LeeDistance extends AbstractPermutationDistanceMeasurer { */ public LeeDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/RTypeDistance.java b/src/org/cicirello/permutations/distance/RTypeDistance.java index 4fcab39c..f54c12b5 100644 --- a/src/org/cicirello/permutations/distance/RTypeDistance.java +++ b/src/org/cicirello/permutations/distance/RTypeDistance.java @@ -53,6 +53,11 @@ public final class RTypeDistance extends AbstractPermutationDistanceMeasurer { */ public RTypeDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/ReinsertionDistance.java b/src/org/cicirello/permutations/distance/ReinsertionDistance.java index 27fc2d0c..47827d81 100644 --- a/src/org/cicirello/permutations/distance/ReinsertionDistance.java +++ b/src/org/cicirello/permutations/distance/ReinsertionDistance.java @@ -67,6 +67,11 @@ public final class ReinsertionDistance extends AbstractPermutationDistanceMeasur */ public ReinsertionDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { diff --git a/src/org/cicirello/permutations/distance/ReversalDistance.java b/src/org/cicirello/permutations/distance/ReversalDistance.java index f79b135b..7d304555 100644 --- a/src/org/cicirello/permutations/distance/ReversalDistance.java +++ b/src/org/cicirello/permutations/distance/ReversalDistance.java @@ -111,6 +111,7 @@ public ReversalDistance(int n) { /** * {@inheritDoc} * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). * @throws IllegalArgumentException if length of the permutations * is not equal to the * the permutation length for which this was configured at time diff --git a/src/org/cicirello/permutations/distance/SquaredDeviationDistance.java b/src/org/cicirello/permutations/distance/SquaredDeviationDistance.java index 4ceefb7e..71fa6dc3 100644 --- a/src/org/cicirello/permutations/distance/SquaredDeviationDistance.java +++ b/src/org/cicirello/permutations/distance/SquaredDeviationDistance.java @@ -54,6 +54,11 @@ public final class SquaredDeviationDistance extends AbstractPermutationDistanceM */ public SquaredDeviationDistance() {} + /** + * {@inheritDoc} + * + * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). + */ @Override public int distance(Permutation p1, Permutation p2) { if (p1.length() != p2.length()) { From 66312d037f75404b91fd76f191b17018d9a6757e Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 29 Jan 2021 14:06:12 -0500 Subject: [PATCH 11/22] Changed default permutation length for ReversalDistance --- src/org/cicirello/permutations/distance/ReversalDistance.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/cicirello/permutations/distance/ReversalDistance.java b/src/org/cicirello/permutations/distance/ReversalDistance.java index 7d304555..52558129 100644 --- a/src/org/cicirello/permutations/distance/ReversalDistance.java +++ b/src/org/cicirello/permutations/distance/ReversalDistance.java @@ -56,10 +56,10 @@ public final class ReversalDistance extends AbstractPermutationDistanceMeasurer private int maxd; /** - * Construct the distance measure. Default handles permutations of length n=10 + * Construct the distance measure. Default handles permutations of length n=5. */ public ReversalDistance() { - this(10); + this(5); } /** From 98094974153971ccd161222e6c72bcb9f77c59e2 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 29 Jan 2021 14:23:05 -0500 Subject: [PATCH 12/22] removed unneeded condition --- src/org/cicirello/permutations/distance/ReversalDistance.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/cicirello/permutations/distance/ReversalDistance.java b/src/org/cicirello/permutations/distance/ReversalDistance.java index 52558129..b0f970b5 100644 --- a/src/org/cicirello/permutations/distance/ReversalDistance.java +++ b/src/org/cicirello/permutations/distance/ReversalDistance.java @@ -88,7 +88,7 @@ public ReversalDistance(int n) { int visited = n * (n-1) / 2 + 1; int start = 1; for (byte d = 1; visited < fact; d++) { - for ( ; start < fact && dist[start] != 0 && dist[start] < d; start++); + for ( ; dist[start] != 0 && dist[start] < d; start++); for (int e = start; e < fact; e++) { if (dist[e] == d) { p = new Permutation(n, e); From 1b894d3756f11e5d3333274cfa583d58bd5b94c5 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 29 Jan 2021 14:23:59 -0500 Subject: [PATCH 13/22] Improved test coverage --- .../distance/PermutationDistanceMaxTests.java | 32 +++++++++++- .../distance/PermutationDistanceTests.java | 49 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/tests/org/cicirello/permutations/distance/PermutationDistanceMaxTests.java b/tests/org/cicirello/permutations/distance/PermutationDistanceMaxTests.java index 4eefb2ed..28ddbf87 100644 --- a/tests/org/cicirello/permutations/distance/PermutationDistanceMaxTests.java +++ b/tests/org/cicirello/permutations/distance/PermutationDistanceMaxTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Vincent A. Cicirello, . + * Copyright 2019-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -32,6 +32,36 @@ public class PermutationDistanceMaxTests { private final static double EPSILON = 1e-10; + @Test + public void testReversalDistance() { + ReversalDistance d = new ReversalDistance(0); + assertEquals(0, d.max(0)); + d = new ReversalDistance(1); + assertEquals(0, d.max(1)); + d = new ReversalDistance(2); + assertEquals(1, d.max(2)); + d = new ReversalDistance(3); + assertEquals(2, d.max(3)); + d = new ReversalDistance(4); + assertEquals(3, d.max(4)); + + final ReversalDistance df = d; + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> df.max(7) + ); + } + + @Test + public void testScrambleDistance() { + ScrambleDistance d = new ScrambleDistance(); + assertEquals(0, d.max(0)); + assertEquals(0, d.max(1)); + for (int n = 2; n <= 10; n++) { + assertEquals(1, d.max(n)); + } + } + @Test public void testBlockInterchangeDistance() { BlockInterchangeDistance d = new BlockInterchangeDistance(); diff --git a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java index 6451b723..227e3d03 100644 --- a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java +++ b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java @@ -32,6 +32,55 @@ public class PermutationDistanceTests { private final static double EPSILON = 1e-10; + @Test + public void testReversalDistance() { + ReversalDistance d4 = new ReversalDistance(4); + int[] a4 = {0, 1, 2, 3}; + int[] a4_2 = {1, 0, 3, 2}; + Permutation p4 = new Permutation(a4); + Permutation p4_2 = new Permutation(a4_2); + assertEquals(2, d4.distance(p4,p4_2)); + ReversalDistance d5 = new ReversalDistance(5); + int[] a5 = {0, 1, 4, 2, 3}; + int[] a5_2 = {1, 0, 4, 3, 2}; + Permutation p5 = new Permutation(a5); + Permutation p5_2 = new Permutation(a5_2); + assertEquals(2, d5.distance(p5,p5_2)); + + ReversalDistance d = new ReversalDistance(); + assertEquals(2, d.distance(p5,p5_2)); + assertEquals(4, d.max(5)); + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d5.distance(new Permutation(5), new Permutation(6)) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d5.distance(new Permutation(6), new Permutation(6)) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> new ReversalDistance(-1) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> new ReversalDistance(13) + ); + } + + @Test + public void testScrambleDistance() { + ScrambleDistance d = new ScrambleDistance(); + identicalPermutations(d); + for (int i = 2; i <= 10; i++) { + Permutation p1 = new Permutation(i); + Permutation p2 = new Permutation(p1); + p2.scramble(true); + assertEquals(1, d.distance(p1,p2)); + } + } + @Test public void testBlockInterchangeDistance() { BlockInterchangeDistance d = new BlockInterchangeDistance(); From a84dea343e4be13728fc09cff525bb7edcf2530a Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 29 Jan 2021 16:17:47 -0500 Subject: [PATCH 14/22] improved test coverage --- .../distance/PermutationDistanceTests.java | 196 +++++++++++++++++- 1 file changed, 194 insertions(+), 2 deletions(-) diff --git a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java index 227e3d03..5436d457 100644 --- a/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java +++ b/tests/org/cicirello/permutations/distance/PermutationDistanceTests.java @@ -32,6 +32,196 @@ public class PermutationDistanceTests { private final static double EPSILON = 1e-10; + @Test + public void testCyclicReversalIndependentDistance() { + ExactMatchDistance em = new ExactMatchDistance(); + CyclicReversalIndependentDistance d = new CyclicReversalIndependentDistance(em); + int[] original = { 0, 1, 2, 3, 4 }; + int[] different = { 3, 4, 0, 2, 1 }; + + Permutation p = new Permutation(original); + Permutation[] rotated = new Permutation[original.length]; + Permutation[] reversed = new Permutation[original.length]; + rotated[0] = new Permutation(original); + for (int i = 1; i < rotated.length; i++) { + rotated[i] = new Permutation(original); + rotated[i].rotate(i); + } + for (int i = 0; i < reversed.length; i++) { + reversed[i] = new Permutation(rotated[i]); + reversed[i].reverse(); + } + for (int i = 0; i < rotated.length; i++) { + assertEquals(0, d.distance(p, rotated[i])); + assertEquals(0, d.distance(p, reversed[i])); + assertEquals(0, d.distancef(p, rotated[i]), EPSILON); + assertEquals(0, d.distancef(p, reversed[i]), EPSILON); + } + rotated[0] = new Permutation(different); + for (int i = 1; i < rotated.length; i++) { + rotated[i] = new Permutation(different); + rotated[i].rotate(i); + } + for (int i = 0; i < reversed.length; i++) { + reversed[i] = new Permutation(rotated[i]); + reversed[i].reverse(); + } + for (int i = 0; i < rotated.length; i++) { + assertEquals(2, d.distance(p, rotated[i])); + assertEquals(2, d.distance(p, reversed[i])); + assertEquals(2, d.distancef(p, rotated[i]), EPSILON); + assertEquals(2, d.distancef(p, reversed[i]), EPSILON); + } + } + + @Test + public void testCyclicReversalIndependentDistanceDouble() { + ExactMatchDistance em = new ExactMatchDistance(); + CyclicReversalIndependentDistanceDouble d = new CyclicReversalIndependentDistanceDouble(em); + int[] original = { 0, 1, 2, 3, 4 }; + int[] different = { 3, 4, 0, 2, 1 }; + + Permutation p = new Permutation(original); + Permutation[] rotated = new Permutation[original.length]; + Permutation[] reversed = new Permutation[original.length]; + rotated[0] = new Permutation(original); + for (int i = 1; i < rotated.length; i++) { + rotated[i] = new Permutation(original); + rotated[i].rotate(i); + } + for (int i = 0; i < reversed.length; i++) { + reversed[i] = new Permutation(rotated[i]); + reversed[i].reverse(); + } + for (int i = 0; i < rotated.length; i++) { + assertEquals(0, d.distancef(p, rotated[i]), EPSILON); + assertEquals(0, d.distancef(p, reversed[i]), EPSILON); + } + rotated[0] = new Permutation(different); + for (int i = 1; i < rotated.length; i++) { + rotated[i] = new Permutation(different); + rotated[i].rotate(i); + } + for (int i = 0; i < reversed.length; i++) { + reversed[i] = new Permutation(rotated[i]); + reversed[i].reverse(); + } + for (int i = 0; i < rotated.length; i++) { + assertEquals(2, d.distancef(p, rotated[i]), EPSILON); + assertEquals(2, d.distancef(p, reversed[i]), EPSILON); + } + } + + @Test + public void testCyclicIndependentDistance() { + ExactMatchDistance em = new ExactMatchDistance(); + CyclicIndependentDistance d = new CyclicIndependentDistance(em); + int[] original = { 0, 1, 2, 3 }; + int[] different = {0, 2, 1, 3 }; + Permutation p1 = new Permutation(original); + Permutation p2 = new Permutation(original); + Permutation pd = new Permutation(different); + Permutation pr1 = new Permutation(p1); + pr1.rotate(1); + Permutation pr2 = new Permutation(p1); + pr1.rotate(2); + Permutation pr3 = new Permutation(p1); + pr1.rotate(3); + assertEquals(0, d.distance(p1, p2)); + assertEquals(0, d.distance(p1, pr1)); + assertEquals(0, d.distance(p1, pr2)); + assertEquals(0, d.distance(p1, pr3)); + assertEquals(2, d.distance(pd, p2)); + assertEquals(2, d.distance(pd, pr1)); + assertEquals(2, d.distance(pd, pr2)); + assertEquals(2, d.distance(pd, pr3)); + + assertEquals(0, d.distancef(p1, p2), EPSILON); + assertEquals(0, d.distancef(p1, pr1), EPSILON); + assertEquals(0, d.distancef(p1, pr2), EPSILON); + assertEquals(0, d.distancef(p1, pr3), EPSILON); + assertEquals(2, d.distancef(pd, p2), EPSILON); + assertEquals(2, d.distancef(pd, pr1), EPSILON); + assertEquals(2, d.distancef(pd, pr2), EPSILON); + assertEquals(2, d.distancef(pd, pr3), EPSILON); + } + + @Test + public void testCyclicIndependentDistanceDouble() { + ExactMatchDistance em = new ExactMatchDistance(); + CyclicIndependentDistanceDouble d = new CyclicIndependentDistanceDouble(em); + int[] original = { 0, 1, 2, 3 }; + int[] different = {0, 2, 1, 3 }; + Permutation p1 = new Permutation(original); + Permutation p2 = new Permutation(original); + Permutation pd = new Permutation(different); + Permutation pr1 = new Permutation(p1); + pr1.rotate(1); + Permutation pr2 = new Permutation(p1); + pr1.rotate(2); + Permutation pr3 = new Permutation(p1); + pr1.rotate(3); + assertEquals(0, d.distancef(p1, p2), EPSILON); + assertEquals(0, d.distancef(p1, pr1), EPSILON); + assertEquals(0, d.distancef(p1, pr2), EPSILON); + assertEquals(0, d.distancef(p1, pr3), EPSILON); + assertEquals(2, d.distancef(pd, p2), EPSILON); + assertEquals(2, d.distancef(pd, pr1), EPSILON); + assertEquals(2, d.distancef(pd, pr2), EPSILON); + assertEquals(2, d.distancef(pd, pr3), EPSILON); + } + + @Test + public void testReversalIndependentDistance() { + ExactMatchDistance em = new ExactMatchDistance(); + ReversalIndependentDistance d = new ReversalIndependentDistance(em); + int[] original = { 0, 1, 2, 3, 4, 5, 6 }; + int[] other = { 0, 5, 4, 3, 2, 1, 6 }; + int[] other2 = { 6, 1, 2, 3, 4, 5, 0 }; + int[] reversed = { 6, 5, 4, 3, 2, 1, 0 }; + Permutation p1 = new Permutation(original); + Permutation p2 = new Permutation(original); + Permutation pr = new Permutation(reversed); + Permutation p4to2 = new Permutation(other); + Permutation p2to4 = new Permutation(other2); + assertEquals(0, d.distance(p1, p2)); + assertEquals(0, d.distance(p1, pr)); + assertEquals(0, d.distance(pr, p2)); + assertEquals(2, d.distance(p1, p4to2)); + assertEquals(2, d.distance(p4to2, p1)); + assertEquals(2, d.distance(p1, p2to4)); + assertEquals(2, d.distance(p2to4, p1)); + assertEquals(0, d.distancef(p1, p2), EPSILON); + assertEquals(0, d.distancef(p1, pr), EPSILON); + assertEquals(0, d.distancef(pr, p2), EPSILON); + assertEquals(2, d.distancef(p1, p4to2), EPSILON); + assertEquals(2, d.distancef(p4to2, p1), EPSILON); + assertEquals(2, d.distancef(p1, p2to4), EPSILON); + assertEquals(2, d.distancef(p2to4, p1), EPSILON); + } + + @Test + public void testReversalIndependentDistanceDouble() { + ExactMatchDistance em = new ExactMatchDistance(); + ReversalIndependentDistanceDouble d = new ReversalIndependentDistanceDouble(em); + int[] original = { 0, 1, 2, 3, 4, 5, 6 }; + int[] other = { 0, 5, 4, 3, 2, 1, 6 }; + int[] other2 = { 6, 1, 2, 3, 4, 5, 0 }; + int[] reversed = { 6, 5, 4, 3, 2, 1, 0 }; + Permutation p1 = new Permutation(original); + Permutation p2 = new Permutation(original); + Permutation pr = new Permutation(reversed); + Permutation p4to2 = new Permutation(other); + Permutation p2to4 = new Permutation(other2); + assertEquals(0, d.distancef(p1, p2), EPSILON); + assertEquals(0, d.distancef(p1, pr), EPSILON); + assertEquals(0, d.distancef(pr, p2), EPSILON); + assertEquals(2, d.distancef(p1, p4to2), EPSILON); + assertEquals(2, d.distancef(p4to2, p1), EPSILON); + assertEquals(2, d.distancef(p1, p2to4), EPSILON); + assertEquals(2, d.distancef(p2to4, p1), EPSILON); + } + @Test public void testReversalDistance() { ReversalDistance d4 = new ReversalDistance(4); @@ -467,6 +657,7 @@ public void testReinsertionDistance() { copy.reverse(); int expected = n-1; assertEquals("maximal distance", expected, d.distance(p,copy)); + assertEquals("maximal distance", expected, d.distance(copy,p)); } int[] a1 = {0, 1, 2, 3, 4, 5}; int[] a2 = {0, 4, 2, 3, 1, 5}; @@ -480,13 +671,14 @@ public void testReinsertionDistance() { assertEquals("all but 3 on longest common subsequence", 3, d.distance(p1,p3)); assertEquals("all but 3 on longest common subsequence", 3, d.distance(p1,p4)); - Permutation p = new Permutation(6); + Permutation p = new Permutation(5); EditDistance edit = new EditDistance(); for (Permutation q : p) { // NOTE: If this assertion fails, problem is either in ReinsertionDistance or EditDistance // Should correspond if they are both correct. assertEquals("equiv of edit with 0.5 cost removes and inserts", edit.distancef(p,q), d.distancef(p,q), EPSILON); - } + assertEquals("equiv of edit with 0.5 cost removes and inserts", edit.distancef(q,p), d.distancef(q,p), EPSILON); + } IllegalArgumentException thrown = assertThrows( IllegalArgumentException.class, From 500d75acb4aafc3afa86aa82f1b0647239de28aa Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Fri, 29 Jan 2021 17:10:42 -0500 Subject: [PATCH 15/22] improved test coverage --- .../distance/SequenceDistanceTests.java | 442 +++++++----------- 1 file changed, 166 insertions(+), 276 deletions(-) diff --git a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java index 5172f08e..99b9c979 100644 --- a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java +++ b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -724,7 +724,9 @@ public void testLongestCommonSubsequenceDistance() { @Test public void testTauObjectSequences() { KendallTauSequenceDistance d = new KendallTauSequenceDistance(); - for (int n = 2; n <= 10; n++) { + assertEquals(0, d.distance(new String[0], new String[0])); + assertEquals(0, d.distance(new ArrayList(), new ArrayList())); + for (int n = 2; n <= 8; n++) { //maximal distance if all unique elements (i.e., a permutation) is reversed sequence String[] s1 = new String[n]; String[] s2 = new String[n]; @@ -747,7 +749,7 @@ public void testTauObjectSequences() { assertEquals("end points swapped", expected, d.distance(toList(s1),toList(s3))); assertEquals("end points swapped", expected, d.distance(toList(s3),toList(s1))); } - for (int n = 2; n <= 10; n++) { + for (int n = 2; n <= 8; n++) { //maximal distance if all unique elements (i.e., a permutation) is reversed sequence NonComparable[] s1 = new NonComparable[n]; NonComparable[] s2 = new NonComparable[n]; @@ -773,7 +775,7 @@ public void testTauObjectSequences() { @Test public void testTauAlg2ObjectSequences() { KendallTauSequenceDistance d = new KendallTauSequenceDistance(true); - for (int n = 2; n <= 10; n++) { + for (int n = 2; n <= 8; n++) { //maximal distance if all unique elements (i.e., a permutation) is reversed sequence String[] s1 = new String[n]; String[] s2 = new String[n]; @@ -796,7 +798,7 @@ public void testTauAlg2ObjectSequences() { assertEquals("end points swapped", expected, d.distance(toList(s1),toList(s3))); assertEquals("end points swapped", expected, d.distance(toList(s3),toList(s1))); } - for (int n = 2; n <= 10; n++) { + for (int n = 2; n <= 8; n++) { //maximal distance if all unique elements (i.e., a permutation) is reversed sequence NonComparable[] s1 = new NonComparable[n]; NonComparable[] s2 = new NonComparable[n]; @@ -819,12 +821,169 @@ public void testTauAlg2ObjectSequences() { } } + @Test + public void testKendallTauDistanceExceptions() { + final KendallTauSequenceDistance d = new KendallTauSequenceDistance(); + + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new int[3], new int[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new long[3], new long[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new short[3], new short[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new byte[3], new byte[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new double[3], new double[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new float[3], new float[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new boolean[3], new boolean[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new char[3], new char[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(new String[3], new String[4]) + ); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance("hello", "hello again") + ); + final ArrayList s1 = new ArrayList(); + final ArrayList s2 = new ArrayList(); + s1.add("a"); + s1.add("b"); + s2.add("a"); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(s1, s2) + ); + } + + @Test + public void testKendallTauDistanceExceptionsDiffElements() { + final KendallTauSequenceDistance d = new KendallTauSequenceDistance(); + helperKendallTauDistanceExceptionsDiffElements(d); + } + + @Test + public void testKendallTauDistanceExceptionsDiffElementsAlg2() { + final KendallTauSequenceDistance d = new KendallTauSequenceDistance(true); + helperKendallTauDistanceExceptionsDiffElements(d); + } + + private void helperKendallTauDistanceExceptionsDiffElements(final KendallTauSequenceDistance d) { + + final int[] i1 = { 1, 2, 3 }; + final int[] i2 = { 1, 2, 4 }; + IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(i1, i2) + ); + final String[] str1 = {"a", "a", "c"}; + final String[] str2 = {"a", "a", "d"}; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(str1, str2) + ); + final ArrayList aL1 = new ArrayList(); + final ArrayList aL2 = new ArrayList(); + for (String e : str1) aL1.add(e); + for (String e : str2) aL2.add(e); + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(aL1, aL2) + ); + final double[] d1 = { 1, 2, 3 }; + final double[] d2 = { 1, 2, 4 }; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(d1, d2) + ); + final float[] f1 = { 1f, 2f, 3f }; + final float[] f2 = { 1f, 2f, 4f }; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(f1, f2) + ); + final long[] L1 = { 1, 2, 3 }; + final long[] L2 = { 1, 2, 4 }; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(L1, L2) + ); + final short[] sh1 = { 1, 2, 3 }; + final short[] sh2 = { 1, 2, 4 }; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(sh1, sh2) + ); + final byte[] b1 = { 1, 2, 3 }; + final byte[] b2 = { 1, 2, 4 }; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(b1, b2) + ); + final char[] ch1 = { '1', '2', '3' }; + final char[] ch2 = { '1', '2', '4' }; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(ch1, ch2) + ); + final String g1 = "123"; + final String g2 = "124"; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(g1, g2) + ); + final boolean[] bool1 = { false, false, true }; + final boolean[] bool2 = { false, false, false }; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(bool1, bool2) + ); + } + @Test public void testKendallTauDistance() { KendallTauSequenceDistance d = new KendallTauSequenceDistance(); identicalSequences(d); + helperForKendallTauCases(d); + } + + @Test + public void testKendallTauDistanceAlg2() { + KendallTauSequenceDistance d = new KendallTauSequenceDistance(true); + identicalSequences(d); + helperForKendallTauCases(d); + } + + @Test + public void testKendallTauDistanceAlg1() { + KendallTauSequenceDistance d = new KendallTauSequenceDistance(false); + identicalSequences(d); + helperForKendallTauCases(d); + } + + private void helperForKendallTauCases(KendallTauSequenceDistance d) { // test first with simpler cases: all unique elements - for (int n = 2; n <= 10; n++) { + for (int n = 2; n <= 8; n++) { //maximal distance if all unique elements (i.e., a permutation) is reversed sequence int[] s1 = new int[n]; int[] s2 = new int[n]; @@ -1171,276 +1330,7 @@ public void testKendallTauDistance() { } } - @Test - public void testKendallTauDistanceAlg2() { - KendallTauSequenceDistance d = new KendallTauSequenceDistance(true); - identicalSequences(d); - // test first with simpler cases: all unique elements - for (int n = 2; n <= 10; n++) { - //maximal distance if all unique elements (i.e., a permutation) is reversed sequence - int[] s1 = new int[n]; - int[] s2 = new int[n]; - int[] s3 = new int[n]; - for (int i = 0; i < n; i++) { - s3[i] = s1[i] = s2[n-1-i] = i+2; - // deliberately didn't use 0 to n-1 for a bit of white box testing (i.e., testing the indexing into arrays of queues) - } - s3[0] = s2[0]; - s3[n-1] = s2[n-1]; - int expected = n*(n-1)/2; - assertEquals("maximal distance", expected, d.distance(s1,s2)); - assertEquals("maximal distance", expected, d.distance(s2,s1)); - expected = 2*n-3; - assertEquals("end points swapped", expected, d.distance(s1,s3)); - assertEquals("end points swapped", expected, d.distance(s3,s1)); - { // long - long[] t1 = new long[n]; - long[] t2 = new long[n]; - long[] t3 = new long[n]; - for (int i = 0; i < n; i++) { - t1[i] = s1[i]; t2[i] = s2[i]; t3[i] = s3[i]; - } - expected = n*(n-1)/2; - assertEquals("maximal distance", expected, d.distance(t1,t2)); - assertEquals("maximal distance", expected, d.distance(t2,t1)); - expected = 2*n-3; - assertEquals("end points swapped", expected, d.distance(t1,t3)); - assertEquals("end points swapped", expected, d.distance(t3,t1)); - } - { // short - short[] t1 = new short[n]; - short[] t2 = new short[n]; - short[] t3 = new short[n]; - for (int i = 0; i < n; i++) { - t1[i] = (short)s1[i]; t2[i] = (short)s2[i]; t3[i] = (short)s3[i]; - } - expected = n*(n-1)/2; - assertEquals("maximal distance", expected, d.distance(t1,t2)); - assertEquals("maximal distance", expected, d.distance(t2,t1)); - expected = 2*n-3; - assertEquals("end points swapped", expected, d.distance(t1,t3)); - assertEquals("end points swapped", expected, d.distance(t3,t1)); - } - { // byte - byte[] t1 = new byte[n]; - byte[] t2 = new byte[n]; - byte[] t3 = new byte[n]; - for (int i = 0; i < n; i++) { - t1[i] = (byte)s1[i]; t2[i] = (byte)s2[i]; t3[i] = (byte)s3[i]; - } - expected = n*(n-1)/2; - assertEquals("maximal distance", expected, d.distance(t1,t2)); - assertEquals("maximal distance", expected, d.distance(t2,t1)); - expected = 2*n-3; - assertEquals("end points swapped", expected, d.distance(t1,t3)); - assertEquals("end points swapped", expected, d.distance(t3,t1)); - } - { // char - char[] t1 = new char[n]; - char[] t2 = new char[n]; - char[] t3 = new char[n]; - for (int i = 0; i < n; i++) { - t1[i] = (char)s1[i]; t2[i] = (char)s2[i]; t3[i] = (char)s3[i]; - } - expected = n*(n-1)/2; - assertEquals("maximal distance", expected, d.distance(t1,t2)); - assertEquals("maximal distance", expected, d.distance(t2,t1)); - expected = 2*n-3; - assertEquals("end points swapped", expected, d.distance(t1,t3)); - assertEquals("end points swapped", expected, d.distance(t3,t1)); - String u1 = new String(t1); - String u2 = new String(t2); - String u3 = new String(t3); - expected = n*(n-1)/2; - assertEquals("maximal distance", expected, d.distance(u1,u2)); - assertEquals("maximal distance", expected, d.distance(u2,u1)); - expected = 2*n-3; - assertEquals("end points swapped", expected, d.distance(u1,u3)); - assertEquals("end points swapped", expected, d.distance(u3,u1)); - } - { // float - float[] t1 = new float[n]; - float[] t2 = new float[n]; - float[] t3 = new float[n]; - for (int i = 0; i < n; i++) { - t1[i] = s1[i]; t2[i] = s2[i]; t3[i] = s3[i]; - } - expected = n*(n-1)/2; - assertEquals("maximal distance", expected, d.distance(t1,t2)); - assertEquals("maximal distance", expected, d.distance(t2,t1)); - expected = 2*n-3; - assertEquals("end points swapped", expected, d.distance(t1,t3)); - assertEquals("end points swapped", expected, d.distance(t3,t1)); - } - { // double - double[] t1 = new double[n]; - double[] t2 = new double[n]; - double[] t3 = new double[n]; - for (int i = 0; i < n; i++) { - t1[i] = s1[i]; t2[i] = s2[i]; t3[i] = s3[i]; - } - expected = n*(n-1)/2; - assertEquals("maximal distance", expected, d.distance(t1,t2)); - assertEquals("maximal distance", expected, d.distance(t2,t1)); - expected = 2*n-3; - assertEquals("end points swapped", expected, d.distance(t1,t3)); - assertEquals("end points swapped", expected, d.distance(t3,t1)); - } - } - Permutation p = new Permutation(6); - int[] s1 = new int[6]; - for (int i = 0; i < 6; i++) s1[i] = p.get(i); - int[] s2 = new int[6]; - for (Permutation q : p) { - for (int i = 0; i < 6; i++) s2[i] = q.get(i); - int expected = naiveKendalTau(s1,s2); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(s1,s2)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(s2,s1)); - } - { // long - s1 = new int[5]; - s2 = new int[5]; - Permutation r = new Permutation(5); - long[] t1 = new long[5]; - for (int i = 0; i < 5; i++) t1[i] = s1[i] = r.get(i); - long[] t2 = new long[5]; - for (Permutation q : r) { - for (int i = 0; i < 5; i++) t2[i] = s2[i] = q.get(i); - int expected = naiveKendalTau(s1,s2); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t1,t2)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t2,t1)); - } - } - { // short - s1 = new int[5]; - s2 = new int[5]; - Permutation r = new Permutation(5); - short[] t1 = new short[5]; - for (int i = 0; i < 5; i++) s1[i] = t1[i] = (short)r.get(i); - short[] t2 = new short[5]; - for (Permutation q : r) { - for (int i = 0; i < 5; i++) s2[i] = t2[i] = (short)q.get(i); - int expected = naiveKendalTau(s1,s2); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t1,t2)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t2,t1)); - } - } - { // byte - s1 = new int[5]; - s2 = new int[5]; - Permutation r = new Permutation(5); - byte[] t1 = new byte[5]; - for (int i = 0; i < 5; i++) s1[i] = t1[i] = (byte)r.get(i); - byte[] t2 = new byte[5]; - for (Permutation q : r) { - for (int i = 0; i < 5; i++) s2[i] = t2[i] = (byte)q.get(i); - int expected = naiveKendalTau(s1,s2); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t1,t2)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t2,t1)); - } - } - { // char - s1 = new int[5]; - s2 = new int[5]; - Permutation r = new Permutation(5); - char[] t1 = new char[5]; - for (int i = 0; i < 5; i++) s1[i] = t1[i] = (char)r.get(i); - String u1 = new String(t1); - char[] t2 = new char[5]; - for (Permutation q : r) { - for (int i = 0; i < 5; i++) s2[i] = t2[i] = (char)q.get(i); - String u2 = new String(t2); - int expected = naiveKendalTau(s1,s2); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t1,t2)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t2,t1)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(u1,u2)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(u2,u1)); - } - } - { // float - s1 = new int[5]; - s2 = new int[5]; - Permutation r = new Permutation(5); - float[] t1 = new float[5]; - for (int i = 0; i < 5; i++) t1[i] = s1[i] = r.get(i); - float[] t2 = new float[5]; - for (Permutation q : r) { - for (int i = 0; i < 5; i++) t2[i] = s2[i] = q.get(i); - int expected = naiveKendalTau(s1,s2); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t1,t2)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t2,t1)); - } - } - { // double - s1 = new int[5]; - s2 = new int[5]; - Permutation r = new Permutation(5); - double[] t1 = new double[5]; - for (int i = 0; i < 5; i++) t1[i] = s1[i] = r.get(i); - double[] t2 = new double[5]; - for (Permutation q : r) { - for (int i = 0; i < 5; i++) t2[i] = s2[i] = q.get(i); - int expected = naiveKendalTau(s1,s2); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t1,t2)); - assertEquals("checking consistence with naive implementation of unique element version", expected, d.distance(t2,t1)); - } - } - // Now test with duplicate elements - String t1 = "abcdaabb"; - String t2 = "dcbababa"; - assertEquals("case where discordant pair counting fails", 9, d.distance(t1,t2)); - assertEquals("case where discordant pair counting fails", 9, d.distance(t2,t1)); - char[] c1 = t1.toCharArray(); - char[] c2 = t2.toCharArray(); - long[] L1 = new long[c1.length]; - long[] L2 = new long[c2.length]; - short[] sh1 = new short[c1.length]; - short[] sh2 = new short[c2.length]; - byte[] b1 = new byte[c1.length]; - byte[] b2 = new byte[c2.length]; - int[] i1 = new int[c1.length]; - int[] i2 = new int[c2.length]; - float[] f1 = new float[c1.length]; - float[] f2 = new float[c2.length]; - double[] d1 = new double[c1.length]; - double[] d2 = new double[c2.length]; - for (int i = 0; i < c1.length; i++) { - L1[i] = i1[i] = c1[i]; - d1[i] = f1[i] = i1[i]; - sh1[i] = (short)c1[i]; - b1[i] = (byte)c1[i]; - L2[i] = i2[i] = c2[i]; - d2[i] = f2[i] = i2[i]; - sh2[i] = (short)c2[i]; - b2[i] = (byte)c2[i]; - } - assertEquals("case where discordant pair counting fails", 9, d.distance(c1,c2)); - assertEquals("case where discordant pair counting fails", 9, d.distance(c2,c1)); - assertEquals("case where discordant pair counting fails", 9, d.distance(L1,L2)); - assertEquals("case where discordant pair counting fails", 9, d.distance(L2,L1)); - assertEquals("case where discordant pair counting fails", 9, d.distance(sh1,sh2)); - assertEquals("case where discordant pair counting fails", 9, d.distance(sh2,sh1)); - assertEquals("case where discordant pair counting fails", 9, d.distance(b1,b2)); - assertEquals("case where discordant pair counting fails", 9, d.distance(b2,b1)); - assertEquals("case where discordant pair counting fails", 9, d.distance(i1,i2)); - assertEquals("case where discordant pair counting fails", 9, d.distance(i2,i1)); - assertEquals("case where discordant pair counting fails", 9, d.distance(f1,f2)); - assertEquals("case where discordant pair counting fails", 9, d.distance(f2,f1)); - assertEquals("case where discordant pair counting fails", 9, d.distance(d1,d2)); - assertEquals("case where discordant pair counting fails", 9, d.distance(d2,d1)); - for (int n = 2; n < 8; n++) { - for (int i = 1; i < n; i++) { - boolean[] a1 = new boolean[n]; - boolean[] a2 = new boolean[n]; - for (int j = 0; j < i; j++) { - a2[j] = a1[n-1-j] = true; - } - int expected = i * (n-i); - assertEquals("boolean case", expected, d.distance(a2,a1)); - assertEquals("boolean case", expected, d.distance(a1,a2)); - } - } - } + // simple naive O(n^2) version if elements are all unique private int naiveKendalTau(int[] s1, int[] s2) { From 2d8fa6fb2066be036f9310de083db58bec891768 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Sat, 30 Jan 2021 13:19:45 -0500 Subject: [PATCH 16/22] Bug fix: distance between arrays of floats --- CHANGELOG.md | 1 + .../distance/KendallTauSequenceDistance.java | 13 +++++-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb69905a..03ee0ca1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Bug in Permutation.toString which was inserting an extra space at end. * Added validation checking for all permutation distance measures validating same length permutations (except for EditDistance which can handle that case). * Bug in ReversalDistance.max in case when permutation length is 2, and also added missing parameter validation. +* Minor bug fix in KendallTauSequenceDistance in the case of distance between arrays of floats. ### CI/CD * Migrated build process from Ant to Maven, including GitHub workflows. diff --git a/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java b/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java index d3919d8a..d8947808 100644 --- a/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java +++ b/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Vincent A. Cicirello, . + * Copyright 2018-2021 Vincent A. Cicirello, . * * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). * @@ -72,13 +72,12 @@ * assumes permutations of the integers from 0 to N-1.

* *

This distance metric, and both algorithms, is first described in the paper:
- * V.A. Cicirello, "Kendall Tau + * V.A. Cicirello, "Kendall Tau * Sequence Distance: Extending Kendall Tau from Ranks to Sequences," - * arXiv preprint arXiv:1905.02752 [cs.DM], May 2019.

+ * Industrial Networks and Intelligent Systems, 7(23), Article e1, April 2020.

* * @author Vincent A. Cicirello, https://www.cicirello.org/ - * @version 1.19.6.10 - * @since 1.1 + * @version 1.30.2021 */ public final class KendallTauSequenceDistance extends AbstractSequenceDistanceMeasurer { @@ -112,8 +111,6 @@ public KendallTauSequenceDistance() { * cost to hash objects, or if the objects are of a class that implements Comparable but * which does not provide an implementation of hashCode.

* - * @since 1.2.3 - * * @param useAlternateAlg To use the alternate algorithm pass true. To use the default algorithm pass false. */ public KendallTauSequenceDistance(boolean useAlternateAlg) { @@ -411,7 +408,7 @@ private int relabelElementsWithHash(double[] s1, double[] s2, int[][] relabeling } private int relabelElementsWithHash(float[] s1, float[] s2, int[][] relabeling) { - DoubleHT labelMap = new DoubleHT((int)(1.334 * relabeling.length)+2); + FloatHT labelMap = new FloatHT((int)(1.334 * relabeling.length)+2); int current = -1; for (int i = 0; i < relabeling.length; i++) { if (!labelMap.containsKey(s1[i])) { From b94d18be1486ee6d1e27716c8cc9f14ca3cfd65d Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Sat, 30 Jan 2021 13:36:41 -0500 Subject: [PATCH 17/22] improved test coverage --- .../sequences/distance/SequenceDistanceTests.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java index 99b9c979..91dc159d 100644 --- a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java +++ b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java @@ -958,6 +958,17 @@ private void helperKendallTauDistanceExceptionsDiffElements(final KendallTauSequ IllegalArgumentException.class, () -> d.distance(bool1, bool2) ); + final String diffCounts1 = "ababa"; + final String diffCounts2 = "babab"; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(diffCounts1, diffCounts2) + ); + final String diffCounts3 = "aaaab"; + thrown = assertThrows( + IllegalArgumentException.class, + () -> d.distance(diffCounts1, diffCounts3) + ); } @Test From 7f0ac8693074d1a0bf8bd739cd87fde7aaf5830e Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Sat, 30 Jan 2021 13:57:39 -0500 Subject: [PATCH 18/22] refactored internal helper classes for hash tables --- .../distance/KendallTauSequenceDistance.java | 132 +++++------------- 1 file changed, 36 insertions(+), 96 deletions(-) diff --git a/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java b/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java index d8947808..3c4dfc31 100644 --- a/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java +++ b/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java @@ -812,13 +812,13 @@ static final class Node { } } - private static final class IntHT { + static class BaseHT { + private final int MAX_SIZE; + protected final int mask; + protected final int minSize; - private Node[] table; - private static final int MAX_SIZE = 0x40000000; - private int mask; - - IntHT(int minSize) { + BaseHT(int maxSize, int minSize) { + MAX_SIZE = maxSize; if (minSize > MAX_SIZE) { minSize = MAX_SIZE; mask = minSize - 1; @@ -832,6 +832,16 @@ private static final class IntHT { mask = minSize; minSize++; } + this.minSize = minSize; + } + } + + private static final class IntHT extends BaseHT { + + private final Node[] table; + + IntHT(int min) { + super(0x40000000, min); table = new Node[minSize]; } @@ -872,26 +882,12 @@ static final class Node { } } - private static final class LongHT { + private static final class LongHT extends BaseHT { - private Node[] table; - private static final int MAX_SIZE = 0x40000000; - private int mask; + private final Node[] table; - LongHT(int minSize) { - if (minSize > MAX_SIZE) { - minSize = MAX_SIZE; - mask = minSize - 1; - } else { - minSize = minSize - 1; - minSize = minSize | (minSize >> 1); - minSize = minSize | (minSize >> 2); - minSize = minSize | (minSize >> 4); - minSize = minSize | (minSize >> 8); - minSize = minSize | (minSize >> 16); - mask = minSize; - minSize++; - } + LongHT(int min) { + super(0x40000000, min); table = new Node[minSize]; } @@ -933,26 +929,12 @@ static final class Node { } } - private static final class ShortHT { + private static final class ShortHT extends BaseHT { - private Node[] table; - private static final int MAX_SIZE = 0x10000; - private int mask; + private final Node[] table; - ShortHT(int minSize) { - if (minSize > MAX_SIZE) { - minSize = MAX_SIZE; - mask = minSize - 1; - } else { - minSize = minSize - 1; - minSize = minSize | (minSize >> 1); - minSize = minSize | (minSize >> 2); - minSize = minSize | (minSize >> 4); - minSize = minSize | (minSize >> 8); - minSize = minSize | (minSize >> 16); - mask = minSize; - minSize++; - } + ShortHT(int min) { + super(0x10000, min); table = new Node[minSize]; } @@ -993,26 +975,12 @@ static final class Node { } } - private static final class CharHT { + private static final class CharHT extends BaseHT { - private Node[] table; - private static final int MAX_SIZE = 0x10000; - private int mask; + private final Node[] table; - CharHT(int minSize) { - if (minSize > MAX_SIZE) { - minSize = MAX_SIZE; - mask = minSize - 1; - } else { - minSize = minSize - 1; - minSize = minSize | (minSize >> 1); - minSize = minSize | (minSize >> 2); - minSize = minSize | (minSize >> 4); - minSize = minSize | (minSize >> 8); - minSize = minSize | (minSize >> 16); - mask = minSize; - minSize++; - } + CharHT(int min) { + super(0x10000, min); table = new Node[minSize]; } @@ -1053,26 +1021,12 @@ static final class Node { } } - private static final class DoubleHT { + private static final class DoubleHT extends BaseHT { - private Node[] table; - private static final int MAX_SIZE = 0x40000000; - private int mask; + private final Node[] table; - DoubleHT(int minSize) { - if (minSize > MAX_SIZE) { - minSize = MAX_SIZE; - mask = minSize - 1; - } else { - minSize = minSize - 1; - minSize = minSize | (minSize >> 1); - minSize = minSize | (minSize >> 2); - minSize = minSize | (minSize >> 4); - minSize = minSize | (minSize >> 8); - minSize = minSize | (minSize >> 16); - mask = minSize; - minSize++; - } + DoubleHT(int min) { + super(0x40000000, min); table = new Node[minSize]; } @@ -1115,26 +1069,12 @@ static final class Node { } } - private static final class FloatHT { + private static final class FloatHT extends BaseHT { - private Node[] table; - private static final int MAX_SIZE = 0x40000000; - private int mask; + private final Node[] table; - FloatHT(int minSize) { - if (minSize > MAX_SIZE) { - minSize = MAX_SIZE; - mask = minSize - 1; - } else { - minSize = minSize - 1; - minSize = minSize | (minSize >> 1); - minSize = minSize | (minSize >> 2); - minSize = minSize | (minSize >> 4); - minSize = minSize | (minSize >> 8); - minSize = minSize | (minSize >> 16); - mask = minSize; - minSize++; - } + FloatHT(int min) { + super(0x40000000, min); table = new Node[minSize]; } From e58a972af05817cdf93cdbf73354dd0e02c144c6 Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Sat, 30 Jan 2021 14:12:09 -0500 Subject: [PATCH 19/22] improved test coverage --- .../distance/KendallTauSequenceDistance.java | 3 +- .../distance/SequenceDistanceTests.java | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java b/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java index 3c4dfc31..0b5f6dab 100644 --- a/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java +++ b/src/org/cicirello/sequences/distance/KendallTauSequenceDistance.java @@ -813,12 +813,11 @@ static final class Node { } static class BaseHT { - private final int MAX_SIZE; protected final int mask; protected final int minSize; BaseHT(int maxSize, int minSize) { - MAX_SIZE = maxSize; + final int MAX_SIZE = maxSize; if (minSize > MAX_SIZE) { minSize = MAX_SIZE; mask = minSize - 1; diff --git a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java index 91dc159d..e6767b0b 100644 --- a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java +++ b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java @@ -876,6 +876,37 @@ public void testKendallTauDistanceExceptions() { ); } + @Test + public void testKendallTauSequenceDistance_HashTableBaseClass() { + class TestHT extends KendallTauSequenceDistance.BaseHT { + TestHT(int min) { + super(32, min); + } + } + for (int n = 1; n <= 32; n *= 2) { + TestHT ht = new TestHT(n); + assertEquals(n, ht.minSize); + assertEquals(n-1, ht.mask); + } + TestHT ht = new TestHT(3); + assertEquals(4, ht.minSize); + for (int n = 5; n < 8; n++) { + ht = new TestHT(n); + assertEquals(8, ht.minSize); + assertEquals(7, ht.mask); + } + for (int n = 9; n < 16; n++) { + ht = new TestHT(n); + assertEquals(16, ht.minSize); + assertEquals(15, ht.mask); + } + for (int n = 17; n <= 64; n++) { + ht = new TestHT(n); + assertEquals(32, ht.minSize); + assertEquals(31, ht.mask); + } + } + @Test public void testKendallTauDistanceExceptionsDiffElements() { final KendallTauSequenceDistance d = new KendallTauSequenceDistance(); From 26b6e0cd31bb9280ca70b6a7bd2c135df6770b6a Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Sat, 30 Jan 2021 14:23:34 -0500 Subject: [PATCH 20/22] improved test coverage --- .../distance/SequenceDistanceTests.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java index e6767b0b..9473aa03 100644 --- a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java +++ b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java @@ -50,9 +50,15 @@ public void testEMObjectSequences() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); assertEquals("maximal distance", 6, d.distance(toList(a1),toList(a2))); assertEquals("end points differ", 2, d.distance(toList(a1),toList(a3))); assertEquals("differ in interior positions", 2, d.distance(toList(a1),toList(a4))); + assertEquals("maximal distance", 6, d.distancef(toList(a1),toList(a2)), EPSILON); + assertEquals("end points differ", 2, d.distancef(toList(a1),toList(a3)), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(toList(a1),toList(a4)), EPSILON); String[] b1 = {"a", "b", "c", "d", "e", "f", "g", "h", "i"}; String[] b2 = {"f", "a", "b", "c", "d", "e", "g", "h", "i"}; String[] b3 = {"f", "b", "c", "d", "e", "a", "g", "h", "i"}; @@ -129,6 +135,9 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); int[] b1 = {0, 1, 2, 3, 4, 5, 6, 7, 8}; int[] b2 = {5, 0, 1, 2, 3, 4, 6, 7, 8}; int[] b3 = {5, 1, 2, 3, 4, 0, 6, 7, 8}; @@ -151,6 +160,9 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); long[] b1 = {0, 1, 2, 3, 4, 5, 6, 7, 8}; long[] b2 = {5, 0, 1, 2, 3, 4, 6, 7, 8}; long[] b3 = {5, 1, 2, 3, 4, 0, 6, 7, 8}; @@ -173,6 +185,9 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); short[] b1 = {0, 1, 2, 3, 4, 5, 6, 7, 8}; short[] b2 = {5, 0, 1, 2, 3, 4, 6, 7, 8}; short[] b3 = {5, 1, 2, 3, 4, 0, 6, 7, 8}; @@ -195,6 +210,9 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); byte[] b1 = {0, 1, 2, 3, 4, 5, 6, 7, 8}; byte[] b2 = {5, 0, 1, 2, 3, 4, 6, 7, 8}; byte[] b3 = {5, 1, 2, 3, 4, 0, 6, 7, 8}; @@ -217,6 +235,9 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); String s1 = new String(a1); String s2 = new String(a2); String s3 = new String(a3); @@ -249,6 +270,15 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 9, d.distance(t2,s1)); assertEquals("end points of shorter differ", 5, d.distance(t3,s1)); assertEquals("differ in interior positions", 5, d.distance(t4,s1)); + + assertEquals("identical except for extras", 3, d.distancef(s1,t1), EPSILON); + assertEquals("maximal distance", 9, d.distancef(s1,t2), EPSILON); + assertEquals("end points of shorter differ", 5, d.distancef(s1,t3), EPSILON); + assertEquals("differ in interior positions", 5, d.distancef(s1,t4), EPSILON); + assertEquals("identical except for extras", 3, d.distancef(t1,s1), EPSILON); + assertEquals("maximal distance", 9, d.distancef(t2,s1), EPSILON); + assertEquals("end points of shorter differ", 5, d.distancef(t3,s1), EPSILON); + assertEquals("differ in interior positions", 5, d.distancef(t4,s1), EPSILON); } { // double double[] a1 = {0, 1, 2, 3, 4, 5}; @@ -258,6 +288,9 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); double[] b1 = {0, 1, 2, 3, 4, 5, 6, 7, 8}; double[] b2 = {5, 0, 1, 2, 3, 4, 6, 7, 8}; double[] b3 = {5, 1, 2, 3, 4, 0, 6, 7, 8}; @@ -280,6 +313,9 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); float[] b1 = {0, 1, 2, 3, 4, 5, 6, 7, 8}; float[] b2 = {5, 0, 1, 2, 3, 4, 6, 7, 8}; float[] b3 = {5, 1, 2, 3, 4, 0, 6, 7, 8}; @@ -302,6 +338,9 @@ public void testExactMatchDistance() { assertEquals("maximal distance", 6, d.distance(a1,a2)); assertEquals("end points differ", 2, d.distance(a1,a3)); assertEquals("differ in interior positions", 2, d.distance(a1,a4)); + assertEquals("maximal distance", 6, d.distancef(a1,a2), EPSILON); + assertEquals("end points differ", 2, d.distancef(a1,a3), EPSILON); + assertEquals("differ in interior positions", 2, d.distancef(a1,a4), EPSILON); boolean[] b1 = {false, true, false, true, false, true, true, true, true}; boolean[] b2 = {true, false, true, false, true, false, false, false, false}; boolean[] b3 = {true, true, false, true, false, false, true, true, true}; From 024625969eb0bf5b78b30b1ca7c3295d7f9e88de Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Sat, 30 Jan 2021 14:42:12 -0500 Subject: [PATCH 21/22] improved test coverage --- .../distance/SequenceDistanceTests.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java index 9473aa03..3a2fab33 100644 --- a/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java +++ b/tests/org/cicirello/sequences/distance/SequenceDistanceTests.java @@ -357,6 +357,80 @@ public void testExactMatchDistance() { } } + @Test + public void testEditDistanceExceptions() { + final EditDistance d = new EditDistance(1.5, 1.5, 1.5); + UnsupportedOperationException thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new int[1], new int[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new long[1], new long[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new short[1], new short[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new byte[1], new byte[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new double[1], new double[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new float[1], new float[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new boolean[1], new boolean[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new char[1], new char[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new String[1], new String[1]) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance(new ArrayList(), new ArrayList()) + ); + thrown = assertThrows( + UnsupportedOperationException.class, + () -> d.distance("a", "a") + ); + + IllegalArgumentException illegal = assertThrows( + IllegalArgumentException.class, + () -> new EditDistance(-1, 0, 0) + ); + illegal = assertThrows( + IllegalArgumentException.class, + () -> new EditDistance(0, -1, 0) + ); + illegal = assertThrows( + IllegalArgumentException.class, + () -> new EditDistance(0, 0, -1) + ); + illegal = assertThrows( + IllegalArgumentException.class, + () -> new EditDistance(-0.01, 0, 0) + ); + illegal = assertThrows( + IllegalArgumentException.class, + () -> new EditDistance(0, -0.01, 0) + ); + illegal = assertThrows( + IllegalArgumentException.class, + () -> new EditDistance(0, 0, -0.01) + ); + } + @Test public void testEditDistance() { EditDistance d = new EditDistance(1, 2, 10); @@ -574,6 +648,12 @@ public void testEditDistance() { assertEquals(45, d.distance(b1,b2)); assertEquals(45.0, d.distancef(b1,b2), EPSILON); } + EditDistance dist1 = new EditDistance(1.1, 2.0, 2.0); + EditDistance dist2 = new EditDistance(2.0, 1.1, 2.0); + EditDistance dist3 = new EditDistance(2.0, 2.0, 1.1); + assertEquals(1.1, dist1.distancef("a", "ab"), EPSILON); + assertEquals(1.1, dist2.distancef("ab", "a"), EPSILON); + assertEquals(1.1, dist3.distancef("a", "b"), EPSILON); } @Test From 0ef35aff27626375edfd4811e87afa680da53fab Mon Sep 17 00:00:00 2001 From: "Vincent A. Cicirello" Date: Sat, 30 Jan 2021 14:47:06 -0500 Subject: [PATCH 22/22] prep for release --- CHANGELOG.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03ee0ca1..e79d9758 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,22 @@ 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] - 2021-01-28 +## [Unreleased] - 2021-01-30 + +### Added + +### Changed + +### Deprecated + +### Removed + +### Fixed + +### CI/CD + + +## [2.3.0] - 2021-01-30 ### Added * Test cases added to improve test coverage. @@ -13,8 +28,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Modified API documentation website (https://jpt.cicirello.org/) to improve browsing on mobile devices. * Minor optimizations in Permutation class. -### Deprecated - ### Removed * Moved the example programs to a new repository. They were previously found in directories examples and replication, both of which have been removed. All of the examples are now located in the repository: https://github.com/cicirello/jpt-examples. * Removed jars of the library from the repo. These have been available from Maven Central, GitHub Packages, and GitHub Releases, for quite some time. No need to store in repo, and it is inefficient to do so.