├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ ├── codeql-analysis.yml │ ├── docs.yml │ ├── manual-deploy-github-only.yml │ ├── manual-deploy.yml │ └── maven-publish.yml ├── .gitignore ├── .zenodo.json ├── CHANGELOG.md ├── CITATION.cff ├── LICENSE ├── README.md ├── paper ├── paper.bib └── paper.md ├── pom.xml ├── spotbugs-exclude.xml └── src ├── main └── java │ ├── module-info.java │ └── org │ └── cicirello │ ├── permutations │ ├── IllegalPermutationStateException.java │ ├── Permutation.java │ ├── PermutationBinaryOperator.java │ ├── PermutationFullBinaryOperator.java │ ├── PermutationFullUnaryOperator.java │ ├── PermutationIterator.java │ ├── PermutationUnaryOperator.java │ ├── distance │ │ ├── AcyclicEdgeDistance.java │ │ ├── BlockInterchangeDistance.java │ │ ├── CycleDistance.java │ │ ├── CycleEditDistance.java │ │ ├── CyclicEdgeDistance.java │ │ ├── CyclicIndependentDistance.java │ │ ├── CyclicIndependentDistanceDouble.java │ │ ├── CyclicRTypeDistance.java │ │ ├── CyclicReversalIndependentDistance.java │ │ ├── CyclicReversalIndependentDistanceDouble.java │ │ ├── DeviationDistance.java │ │ ├── DeviationDistanceNormalized.java │ │ ├── DeviationDistanceNormalized2005.java │ │ ├── EditDistance.java │ │ ├── ExactMatchDistance.java │ │ ├── InterchangeDistance.java │ │ ├── KCycleDistance.java │ │ ├── KendallTauDistance.java │ │ ├── LeeDistance.java │ │ ├── NormalizedPermutationDistanceMeasurer.java │ │ ├── NormalizedPermutationDistanceMeasurerDouble.java │ │ ├── PermutationDistanceMeasurer.java │ │ ├── PermutationDistanceMeasurerDouble.java │ │ ├── RTypeDistance.java │ │ ├── ReinsertionDistance.java │ │ ├── ReversalDistance.java │ │ ├── ReversalIndependentDistance.java │ │ ├── ReversalIndependentDistanceDouble.java │ │ ├── ScrambleDistance.java │ │ ├── SquaredDeviationDistance.java │ │ ├── WeightedKendallTauDistance.java │ │ └── package-info.java │ └── package-info.java │ └── sequences │ ├── SequenceCompositeSampler.java │ ├── SequenceInsertionSampler.java │ ├── SequencePoolSampler.java │ ├── SequenceReservoirSampler.java │ ├── SequenceSampler.java │ ├── SequenceSamplerUtils.java │ ├── distance │ ├── EditDistance.java │ ├── EditDistanceDouble.java │ ├── ExactMatchDistance.java │ ├── KendallTauRelabeler.java │ ├── KendallTauSequenceDistance.java │ ├── LongestCommonSubsequenceDistance.java │ ├── RelabelByHashing.java │ ├── RelabelBySorting.java │ ├── SequenceDistanceMeasurer.java │ ├── SequenceDistanceMeasurerDouble.java │ └── package-info.java │ └── package-info.java └── test └── java └── org └── cicirello ├── permutations ├── PermutationConstructorRelatedTests.java ├── PermutationCycleTests.java ├── PermutationHashCodeCacheTests.java ├── PermutationInverseTests.java ├── PermutationIteratorTests.java ├── PermutationNoncontiguousScrambleTests.java ├── PermutationOperatorsTests.java ├── PermutationRemoveInsertTests.java ├── PermutationReverseTests.java ├── PermutationRotateTests.java ├── PermutationScrambleTests.java ├── PermutationSwapTests.java ├── PermutationToFromArraysTests.java ├── SharedTestHelpersPermutation.java └── distance │ ├── AcyclicEdgeDistanceTests.java │ ├── BlockInterchangeDistanceTests.java │ ├── CycleDistanceTests.java │ ├── CycleEditDistanceTests.java │ ├── CyclicEdgeDistanceTests.java │ ├── CyclicIndependenceTests.java │ ├── CyclicRTypeDistanceTests.java │ ├── CyclicReversalIndependenceTests.java │ ├── DeviationDistanceNormalizedTests.java │ ├── DeviationDistanceTests.java │ ├── EditDistanceTests.java │ ├── ExactMatchDistanceTests.java │ ├── InterchangeDistanceTests.java │ ├── KCycleDistanceTests.java │ ├── KendallTauDistanceTests.java │ ├── LeeDistanceTests.java │ ├── RTypeDistanceTests.java │ ├── ReinsertionDistanceTests.java │ ├── ReversalDistanceTests.java │ ├── ReversalIndependenceTests.java │ ├── ScrambleDistanceTests.java │ ├── SharedTestForPermutationDistance.java │ ├── SharedTestForPermutationDistanceDouble.java │ ├── SquaredDeviationDistanceTests.java │ └── WeightedKendallTauDistanceTests.java └── sequences ├── SequenceSamplerByteTests.java ├── SequenceSamplerCharTests.java ├── SequenceSamplerDoubleTests.java ├── SequenceSamplerFloatTests.java ├── SequenceSamplerIntTests.java ├── SequenceSamplerLongTests.java ├── SequenceSamplerObjectTests.java ├── SequenceSamplerShortTests.java ├── SequenceSamplerStatisticalTests.java ├── SequenceSamplerStringTests.java └── distance ├── EditDistanceDoubleTests.java ├── EditDistanceTests.java ├── ExactMatchDistanceTests.java ├── InternalTestHelpersKendallTau.java ├── InternalTestHelpersSequenceDistance.java ├── KendallTauSequenceDistanceTests.java └── LongestCommonSubsequenceTests.java /.gitattributes: -------------------------------------------------------------------------------- 1 | paper/* linguist-documentation 2 | *.html linguist-documentation 3 | 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "maven" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | target-branch: "master" 11 | schedule: 12 | interval: "daily" 13 | - package-ecosystem: "github-actions" # See documentation for possible values 14 | directory: "/" # Location of package manifests 15 | target-branch: "master" 16 | schedule: 17 | interval: "daily" 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths: [ '**.java', '.github/workflows/build.yml' ] 7 | pull_request: 8 | branches: [ master ] 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Checkout badges branch to a badges directory nested inside first checkout 21 | uses: actions/checkout@v4 22 | with: 23 | ref: badges 24 | path: badges 25 | 26 | - name: Set up JDK 17 27 | uses: actions/setup-java@v4 28 | with: 29 | distribution: 'adopt' 30 | java-version: '17' 31 | 32 | - name: Build with Maven 33 | run: mvn -B package -Pcoverage 34 | 35 | - name: Generate JaCoCo badge 36 | id: jacoco 37 | uses: cicirello/jacoco-badge-generator@v2 38 | with: 39 | badges-directory: badges 40 | generate-branches-badge: true 41 | generate-summary: true 42 | 43 | - name: Log coverage percentages to workflow output 44 | run: | 45 | echo "coverage = ${{ steps.jacoco.outputs.coverage }}" 46 | echo "branches = ${{ steps.jacoco.outputs.branches }}" 47 | 48 | - name: Upload JaCoCo coverage report as a workflow artifact 49 | uses: actions/upload-artifact@v4 50 | with: 51 | name: jacoco-report 52 | path: target/site/jacoco/ 53 | 54 | - name: Commit and push the coverage badges and summary file 55 | if: ${{ github.event_name != 'pull_request' }} 56 | run: | 57 | cd badges 58 | if [[ `git status --porcelain *.svg *.json` ]]; then 59 | git config --global user.name 'github-actions' 60 | git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' 61 | git add *.svg *.json 62 | git commit -m "Autogenerated JaCoCo coverage badges" *.svg *.json 63 | git push 64 | fi 65 | 66 | - name: Comment on PR with coverage percentages 67 | if: ${{ github.event_name == 'pull_request' }} 68 | run: | 69 | REPORT=$( 52 | 53 | 54 | - name: Log javadoc-cleanup output 55 | if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }} 56 | run: | 57 | echo "modified-count = ${{ steps.tidy.outputs.modified-count }}" 58 | 59 | - name: Commit documentation changes without pushing yet 60 | if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }} 61 | run: | 62 | cd gh-pages 63 | if [[ `git status --porcelain` ]]; then 64 | git config --global user.name 'github-actions' 65 | git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' 66 | git add -A 67 | git commit -m "Automated API website updates." 68 | fi 69 | cd .. 70 | 71 | - name: Generate the sitemap 72 | if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }} 73 | id: sitemap 74 | uses: cicirello/generate-sitemap@v1 75 | with: 76 | base-url-path: https://jpt.cicirello.org/ 77 | path-to-root: gh-pages 78 | 79 | - name: Output stats 80 | if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }} 81 | run: | 82 | echo "sitemap-path = ${{ steps.sitemap.outputs.sitemap-path }}" 83 | echo "url-count = ${{ steps.sitemap.outputs.url-count }}" 84 | echo "excluded-count = ${{ steps.sitemap.outputs.excluded-count }}" 85 | 86 | - name: Commit documentation website sitemap and push all commits 87 | if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }} 88 | run: | 89 | cd gh-pages 90 | if [[ `git status --porcelain` ]]; then 91 | git config --global user.name 'github-actions' 92 | git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' 93 | git add -A 94 | git commit -m "Automated API website sitemap update." 95 | fi 96 | git push 97 | cd .. 98 | -------------------------------------------------------------------------------- /.github/workflows/manual-deploy-github-only.yml: -------------------------------------------------------------------------------- 1 | name: Manual Maven Deploy Package GH 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | VERSION: 7 | description: 'The SemVer version number' 8 | required: true 9 | 10 | jobs: 11 | deploygh: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | env: 16 | artifact_name: jpt 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Set up JDK 17 for deploy to github packages 22 | uses: actions/setup-java@v4 23 | with: 24 | distribution: 'adopt' 25 | java-version: '17' 26 | server-id: github 27 | 28 | - name: Build with Maven 29 | run: mvn -B package --file pom.xml 30 | 31 | - name: Update package version 32 | run: mvn versions:set -DnewVersion=${{ github.event.inputs.VERSION }} 33 | 34 | - name: Publish to GitHub Packages Apache Maven 35 | run: mvn deploy -PgithubDeploy 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | -------------------------------------------------------------------------------- /.github/workflows/manual-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Manual Maven Deploy Package 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | VERSION: 7 | description: 'The SemVer version number' 8 | required: true 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | env: 16 | artifact_name: jpt 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Set up JDK 17 21 | uses: actions/setup-java@v4 22 | with: 23 | distribution: 'adopt' 24 | java-version: '17' 25 | server-id: github 26 | 27 | - name: Build with Maven 28 | run: mvn -B package --file pom.xml 29 | 30 | - name: Update package version 31 | run: mvn versions:set -DnewVersion=${{ github.event.inputs.VERSION }} 32 | 33 | - name: Publish to GitHub Packages Apache Maven 34 | run: mvn deploy -PgithubDeploy 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | 38 | 39 | -------------------------------------------------------------------------------- /.github/workflows/maven-publish.yml: -------------------------------------------------------------------------------- 1 | name: Maven Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | env: 13 | artifact_name: jpt 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Get the release version 19 | id: get_version 20 | run: echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_OUTPUT 21 | 22 | - name: Set up JDK 17 for deploy to Central 23 | uses: actions/setup-java@v4 24 | with: 25 | distribution: 'adopt' 26 | java-version: '17' 27 | server-id: central 28 | server-username: MAVEN_USERNAME 29 | server-password: MAVEN_CENTRAL_TOKEN 30 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} 31 | gpg-passphrase: MAVEN_GPG_PASSPHRASE 32 | 33 | - name: Build with Maven 34 | run: mvn -B package --file pom.xml 35 | 36 | - name: Update package version 37 | run: mvn versions:set -DnewVersion=${{ steps.get_version.outputs.VERSION }} 38 | 39 | - name: Publish to Apache Maven Central 40 | run: mvn deploy -PcentralDeploy 41 | env: 42 | MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} 43 | MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} 44 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 45 | 46 | - name: Set up JDK 17 for deploy to github packages 47 | uses: actions/setup-java@v4 48 | with: 49 | distribution: 'adopt' 50 | java-version: '17' 51 | server-id: github 52 | 53 | - name: Publish to GitHub Packages Apache Maven 54 | run: mvn deploy -PgithubDeploy 55 | env: 56 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 57 | 58 | - name: Upload jar files to release as release assets 59 | run: | 60 | TAG=${GITHUB_REF/refs\/tags\//} 61 | gh release upload ${TAG} target/${{ env.artifact_name }}-${{ steps.get_version.outputs.VERSION }}.jar 62 | gh release upload ${TAG} target/${{ env.artifact_name }}-${{ steps.get_version.outputs.VERSION }}-sources.jar 63 | gh release upload ${TAG} target/${{ env.artifact_name }}-${{ steps.get_version.outputs.VERSION }}-javadoc.jar 64 | env: 65 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | exbin/ 3 | testbin/ 4 | target/ 5 | member-search-index.zip 6 | type-search-index.zip 7 | package-search-index.zip 8 | module-search-index.zip 9 | tag-search-index.zip 10 | dependency-reduced-pom.xml 11 | -------------------------------------------------------------------------------- /.zenodo.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JavaPermutationTools", 3 | "license": "GPL-3.0-or-later", 4 | "upload_type": "software", 5 | "creators": [ 6 | { 7 | "orcid": "0000-0003-1072-8559", 8 | "affiliation": "Stockton University", 9 | "name": "Vincent A. Cicirello" 10 | } 11 | ], 12 | "keywords": [ 13 | "permutations", 14 | "sequences", 15 | "permutation distance", 16 | "permutation metric", 17 | "sequence distance", 18 | "string distance", 19 | "edit distance" 20 | ], 21 | "related_identifiers": [ 22 | { 23 | "scheme": "doi", 24 | "identifier": "10.21105/joss.00950", 25 | "relation": "isDocumentedBy", 26 | "resource_type": "publication" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: "1.1.0" 2 | message: "If you use this software, please cite it using these metadata." 3 | authors: 4 | - family-names: "Cicirello" 5 | given-names: "Vincent A" 6 | orcid: "https://orcid.org/0000-0003-1072-8559" 7 | title: "JavaPermutationTools" 8 | doi: "10.5281/zenodo.1478192" 9 | license: "GPL-3.0-or-later" 10 | url: "https://github.com/cicirello/JavaPermutationTools" 11 | preferred-citation: 12 | type: article 13 | authors: 14 | - family-names: "Cicirello" 15 | given-names: "Vincent A" 16 | orcid: "https://orcid.org/0000-0003-1072-8559" 17 | doi: "10.21105/joss.00950" 18 | journal: "Journal of Open Source Software" 19 | start: 950 20 | title: "JavaPermutationTools: A Java Library of Permutation Distance Metrics" 21 | issue: 31 22 | volume: 3 23 | year: 2018 24 | -------------------------------------------------------------------------------- /spotbugs-exclude.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/IllegalPermutationStateException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | /** 25 | * This is a {@link RuntimeException} that is thrown by certain methods of the {@link Permutation} 26 | * class to indicate that the Permutation object's state is invalid, and any subsequent calls to 27 | * methods on that object may be unpredictable. 28 | * 29 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 31 | */ 32 | public class IllegalPermutationStateException extends RuntimeException { 33 | 34 | /** 35 | * Construct an IllegalPermutationStateException without specifying a cause. 36 | * 37 | * @param message A descriptive message about the exception that is thrown. 38 | */ 39 | public IllegalPermutationStateException(String message) { 40 | super(message); 41 | } 42 | 43 | /** 44 | * Construct an IllegalPermutationStateException. 45 | * 46 | * @param message A descriptive message about the exception that is thrown. 47 | * @param cause The cause of the exception. 48 | */ 49 | public IllegalPermutationStateException(String message, Throwable cause) { 50 | super(message, cause); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/PermutationBinaryOperator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | /** 25 | * A functional interface for defining custom binary operators on Permutations. See the {@link 26 | * Permutation#apply(PermutationBinaryOperator,Permutation)} method. 27 | * 28 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 30 | */ 31 | @FunctionalInterface 32 | public interface PermutationBinaryOperator { 33 | 34 | /** 35 | * Applies an operator on the raw representations of a pair of Permutations. Implementers of this 36 | * interface are responsible for ensuring that the apply method maintains valid permutations of 37 | * the integers in {0, 1, ..., rawPermutation1.length - 1 }, and likewise for rawPermutation2. 38 | * 39 | * @param rawPermutation1 A reference to the raw array of ints underlying a Permutation object. 40 | * Changes to this array will directly change the Permutation object that encapsulates it. 41 | * @param rawPermutation2 A reference to the raw array of ints underlying a Permutation object. 42 | * Changes to this array will directly change the Permutation object that encapsulates it. 43 | */ 44 | void apply(int[] rawPermutation1, int[] rawPermutation2); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/PermutationFullBinaryOperator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | /** 25 | * A functional interface for defining custom binary operators on Permutations. See the {@link 26 | * Permutation#apply(PermutationFullBinaryOperator,Permutation)} method. In this interface, the 27 | * {@link #apply} method is passed both references to the raw arrays of ints that are encapsulated 28 | * by the Permutations, as well as references to the original Permutation objects to enable 29 | * utilizing the methods of the {@link Permutation} class. If the operator that you are implementing 30 | * only requires the raw arrays of ints, then consider implementing the {@link 31 | * PermutationBinaryOperator} interface instead. 32 | * 33 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 35 | */ 36 | @FunctionalInterface 37 | public interface PermutationFullBinaryOperator { 38 | 39 | /** 40 | * Applies an operator on the raw representations of a pair of Permutations. Implementers of this 41 | * interface are responsible for ensuring that the apply method maintains valid permutations of 42 | * the integers in {0, 1, ..., rawPermutation1.length - 1 }, and likewise for rawPermutation2. 43 | * 44 | * @param rawPermutation1 A reference to the raw array of ints underlying a Permutation object. 45 | * Changes to this array will directly change the Permutation object that encapsulates it. 46 | * @param rawPermutation2 A reference to the raw array of ints underlying a Permutation object. 47 | * Changes to this array will directly change the Permutation object that encapsulates it. 48 | * @param p1 A reference to the Permutation object that encapsulates rawPermutation1. 49 | * @param p2 A reference to the Permutation object that encapsulates rawPermutation2. 50 | */ 51 | void apply(int[] rawPermutation1, int[] rawPermutation2, Permutation p1, Permutation p2); 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/PermutationFullUnaryOperator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | /** 25 | * A functional interface for defining custom unary operators on Permutations. See the {@link 26 | * Permutation#apply(PermutationFullUnaryOperator)} method. In this interface, the {@link #apply} 27 | * method is passed both a reference to the raw array of ints that is encapsulated by the 28 | * Permutation, as well as a reference to the Permutation object itself to enable utilizing the 29 | * methods of the {@link Permutation} class. If the operator that you are implementing only requires 30 | * the raw array of ints, then consider implementing the {@link PermutationUnaryOperator} interface 31 | * instead. 32 | * 33 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 35 | */ 36 | @FunctionalInterface 37 | public interface PermutationFullUnaryOperator { 38 | 39 | /** 40 | * Applies an operator on the raw representation of a Permutation. Implementers of this interface 41 | * are responsible for ensuring that the apply method maintains a valid permutation of the 42 | * integers in {0, 1, ..., rawPermutation.length - 1 }. 43 | * 44 | * @param rawPermutation A reference to the raw array of ints underlying a Permutation object. 45 | * Changes to this array will directly change the Permutation object that encapsulates it. 46 | * @param p A reference to the Permutation object that encapsulates it. 47 | */ 48 | void apply(int[] rawPermutation, Permutation p); 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/PermutationIterator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | 23 | package org.cicirello.permutations; 24 | 25 | import java.util.Iterator; 26 | import java.util.NoSuchElementException; 27 | import org.cicirello.util.ArrayFiller; 28 | 29 | /** 30 | * Iterator over all permutations of a specified length, n, of the integers in the interval [0,n). 31 | * The runtime of the constructors is O(n), where n is the permutation length. The {@link 32 | * #hasNext()} method is O(1). The runtime of the {@link #next()} method is O(n), as it does O(n) 33 | * swaps in the worst-case, and regardless of number of swaps it returns a copy (an O(n) operation) 34 | * of the internally maintained Permutation object so the caller can safely modify the returned 35 | * Permutation without risk of interfering with the operation of the Iterator. 36 | * 37 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 39 | */ 40 | public class PermutationIterator implements Iterator { 41 | 42 | private final Permutation p; 43 | private final int[] lastSwap; 44 | private boolean done; 45 | 46 | /** 47 | * Initializes a PermutationIterator to iterate over all permutations of a given length. 48 | * Specifically, it iterates over permutations of the first n integers, i.e., the integers in the 49 | * interval [0, n-1]. The first permutation in the iteration is chosen randomly. 50 | * 51 | * @param n The length of the permutations. 52 | */ 53 | public PermutationIterator(int n) { 54 | this(new Permutation(n)); 55 | } 56 | 57 | /** 58 | * Initializes a PermutationIterator to iterate over all permutations the same length as a given 59 | * permutation. Specifically, it iterates over permutations of the first n integers, i.e., the 60 | * integers in the interval [0, n-1). The first permutation in the iteration is specified as a 61 | * parameter. 62 | * 63 | * @param p The first permutation in the iteration. 64 | */ 65 | public PermutationIterator(Permutation p) { 66 | this.p = new Permutation(p); 67 | lastSwap = ArrayFiller.create(p.length()); 68 | done = false; 69 | } 70 | 71 | /** 72 | * Checks if this PermutationIterator has more Permutations. 73 | * 74 | * @return true if and only if this PermutationIterator has more Permutations to iterate over. 75 | */ 76 | @Override 77 | public boolean hasNext() { 78 | return !done; 79 | } 80 | 81 | /** 82 | * Gets the Permutation for the next iteration. 83 | * 84 | * @return The Permutation for the next iteration. 85 | * @throws NoSuchElementException if hasNext() is false 86 | */ 87 | @Override 88 | public Permutation next() { 89 | if (done) throw new NoSuchElementException(); 90 | Permutation n = new Permutation(p); 91 | if (lastSwap.length <= 1) { 92 | done = true; 93 | } else { 94 | for (int i = lastSwap.length - 2; i >= 0; i--) { 95 | if (lastSwap[i] != i) p.internalSwap(i, lastSwap[i]); 96 | if (lastSwap[i] == lastSwap.length - 1) { 97 | lastSwap[i] = i; 98 | if (i == 0) done = true; 99 | continue; 100 | } 101 | lastSwap[i]++; 102 | p.internalSwap(i, lastSwap[i]); 103 | break; 104 | } 105 | } 106 | return n; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/PermutationUnaryOperator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | /** 25 | * A functional interface for defining custom unary operators on Permutations. See the {@link 26 | * Permutation#apply(PermutationUnaryOperator)} method. 27 | * 28 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 30 | */ 31 | @FunctionalInterface 32 | public interface PermutationUnaryOperator { 33 | 34 | /** 35 | * Applies an operator on the raw representation of a Permutation. Implementers of this interface 36 | * are responsible for ensuring that the apply method maintains a valid permutation of the 37 | * integers in {0, 1, ..., rawPermutation.length - 1 }. 38 | * 39 | * @param rawPermutation A reference to the raw array of ints underlying a Permutation object. 40 | * Changes to this array will directly change the Permutation object that encapsulates it. 41 | */ 42 | void apply(int[] rawPermutation); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/AcyclicEdgeDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * Acyclic edge distance treats the permutations as if they represent sets of edges, and counts the 27 | * number of edges that differ. 28 | * 29 | *

Consider the example permutation: [1, 5, 2, 4, 0, 3]. Acyclic edge distance treats this as 30 | * equivalent to the set of undirected edges: {(1,5), (5,2), (2,4), (4,0), (0,3)}. 31 | * 32 | *

E.g., distance between [1, 5, 2, 4, 0, 3] and [ 5, 1, 4, 0, 3, 2] is 2. Why? Well, the first 33 | * permutation has the edges: {(1,5), (5,2), (2,4), (4,0), (0,3)}. The second has three of these 34 | * (5,1), which is the same as (1,5) since they are undirected edges, (4,0), and (0,3), but does not 35 | * include two of the edges: (5,2), (2,4) 36 | * 37 | *

Runtime: O(n), where n is the permutation length. 38 | * 39 | *

Acyclic edge distance was first described in:
40 | * S. Ronald, "Distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 1997, 41 | * pp. 49–54. 42 | * 43 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 45 | */ 46 | public final class AcyclicEdgeDistance implements NormalizedPermutationDistanceMeasurer { 47 | 48 | /** Constructs the distance measurer as specified in the class documentation. */ 49 | public AcyclicEdgeDistance() {} 50 | 51 | /** 52 | * {@inheritDoc} 53 | * 54 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 55 | */ 56 | @Override 57 | public int distance(Permutation p1, Permutation p2) { 58 | if (p1.length() != p2.length()) { 59 | throw new IllegalArgumentException("Permutations must be the same length"); 60 | } 61 | int countNonSharedEdges = 0; 62 | if (p1.length() == 0) return 0; 63 | int[] successors2 = new int[p2.length()]; 64 | for (int i = 0; i < p2.length() - 1; i++) { 65 | successors2[p2.get(i)] = p2.get(i + 1); 66 | } 67 | successors2[p2.get(p2.length() - 1)] = -1; 68 | 69 | for (int i = 0; i < p1.length() - 1; i++) { 70 | if (p1.get(i + 1) != successors2[p1.get(i)] && p1.get(i) != successors2[p1.get(i + 1)]) 71 | countNonSharedEdges++; 72 | } 73 | return countNonSharedEdges; 74 | } 75 | 76 | @Override 77 | public int max(int length) { 78 | if (length <= 2) return 0; 79 | if (length == 3) return 1; 80 | return length - 1; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/BlockInterchangeDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * Block Interchange Distance is the minimum number of block interchanges necessary to transform one 27 | * permutation into the other. A block interchange is an edit operation that takes two 28 | * non-overlapping blocks (i.e., subsequence) and exchanges their locations in the permutation. For 29 | * example, the permutation p1 = [0, 1, 2, 3, 4, 5, 6, 7] and p2 = [5, 6, 3, 4, 0, 1, 2, 7] is a 30 | * block interchange distance of 1 since you can transform p2 into p1 by exchanging the blocks [5, 31 | * 6] and [0, 1, 2] within p2. 32 | * 33 | *

Interchange distance is computed efficiently using the algorithm described in the article: 34 | * D.A. Christie, "Sorting permutations by block-interchanges," Information Processing Letters, vol 35 | * 60, pages 165-169, 1996. 36 | * 37 | *

Runtime: O(n), where n is the permutation length. 38 | * 39 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 41 | */ 42 | public class BlockInterchangeDistance implements NormalizedPermutationDistanceMeasurer { 43 | 44 | /** Constructs the distance measurer as specified in the class documentation. */ 45 | public BlockInterchangeDistance() {} 46 | 47 | /** 48 | * {@inheritDoc} 49 | * 50 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 51 | */ 52 | @Override 53 | public int distance(Permutation p1, Permutation p2) { 54 | if (p1.length() != p2.length()) { 55 | throw new IllegalArgumentException("Permutations must be the same length"); 56 | } 57 | int[] inv2 = p2.getInverse(); 58 | int[] p = new int[inv2.length + 2]; 59 | int[] inv = new int[p.length]; 60 | boolean[] visited = new boolean[p.length]; 61 | for (int i = 0; i < p1.length(); i++) { 62 | int index = inv2[p1.get(i)] + 1; 63 | p[index] = i + 1; 64 | inv[i + 1] = index; 65 | } 66 | p[0] = inv[0] = 0; 67 | p[p.length - 1] = inv[p.length - 1] = p.length - 1; 68 | int cycles = 0; 69 | for (int i = 0; i <= p1.length(); i++) { 70 | if (!visited[i]) { 71 | cycles++; 72 | int j = i; 73 | while (!visited[j]) { 74 | visited[j] = true; 75 | j++; 76 | j = p[inv[j] - 1]; 77 | } 78 | } 79 | } 80 | return (p1.length() + 1 - cycles) / 2; 81 | } 82 | 83 | @Override 84 | public int max(int length) { 85 | return length >> 1; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/CycleDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Cycle distance is the count of the number of non-singleton permutation cycles between a pair of 28 | * permutations. Cycle distance is a semi-metric, satisfying all of the metric properties except for 29 | * the triangle inequality. 30 | * 31 | *

It was introduced in the following article: 32 | * 33 | *

Vincent A. Cicirello. 2022. Cycle Mutation: Evolving 35 | * Permutations via Cycle Induction, Applied Sciences, 12(11), Article 5506 (June 2022). 36 | * doi:10.3390/app12115506 37 | * 38 | *

Runtime: O(n), where n is the permutation length. 39 | * 40 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 42 | */ 43 | public final class CycleDistance implements NormalizedPermutationDistanceMeasurer { 44 | 45 | /** Constructs the distance measurer as specified in the class documentation. */ 46 | public CycleDistance() {} 47 | 48 | /** 49 | * {@inheritDoc} 50 | * 51 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 52 | */ 53 | @Override 54 | public int distance(Permutation p1, Permutation p2) { 55 | if (p1.length() != p2.length()) { 56 | throw new IllegalArgumentException("Permutations must be the same length"); 57 | } 58 | boolean[] used = new boolean[p1.length()]; 59 | for (int k = 0; k < used.length; k++) { 60 | if (p1.get(k) == p2.get(k)) { 61 | used[p1.get(k)] = true; 62 | } 63 | } 64 | int i = 0; 65 | for (i = 0; i < used.length; i++) { 66 | if (!used[p1.get(i)]) { 67 | break; 68 | } 69 | } 70 | 71 | int[] invP1 = p1.getInverse(); 72 | int cycleCount = 0; 73 | int iLast = i; 74 | 75 | while (i < used.length) { 76 | int j = p1.get(i); 77 | while (!used[j]) { 78 | used[j] = true; 79 | j = p2.get(i); 80 | i = invP1[j]; 81 | } 82 | cycleCount++; 83 | for (i = iLast + 1; i < used.length; i++) { 84 | if (!used[p1.get(i)]) { 85 | break; 86 | } 87 | } 88 | iLast = i; 89 | } 90 | return cycleCount; 91 | } 92 | 93 | @Override 94 | public int max(int length) { 95 | return length >> 1; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/CycleEditDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Cycle edit distance is the minimum number of non-singleton permutation cycles necessary to 28 | * transform permutation p1 into p2. If p1 equals p2, then this distance is 0. If p1 and p2 have a 29 | * single permutation cycle, then this distance is clearly 1 since the inverse of that cycle will 30 | * produce n fixed points. Otherwise, this distance is equal to 2 since it can be shown that at most 31 | * 2 permutation cycle operations are necessary to transform any permutation of length n into any 32 | * other. Cycle edit distance satisfies all of the metric properties. 33 | * 34 | *

Cycle edit distance was introduced in the following article: 35 | * 36 | *

Vincent A. Cicirello. 2022. Cycle Mutation: Evolving 38 | * Permutations via Cycle Induction, Applied Sciences, 12(11), Article 5506 (June 2022). 39 | * doi:10.3390/app12115506 40 | * 41 | *

Runtime: O(n), where n is the permutation length. 42 | * 43 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 45 | */ 46 | public final class CycleEditDistance implements NormalizedPermutationDistanceMeasurer { 47 | 48 | /** Constructs the distance measurer as specified in the class documentation. */ 49 | public CycleEditDistance() {} 50 | 51 | /** 52 | * {@inheritDoc} 53 | * 54 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 55 | */ 56 | @Override 57 | public int distance(Permutation p1, Permutation p2) { 58 | if (p1.length() != p2.length()) { 59 | throw new IllegalArgumentException("Permutations must be the same length"); 60 | } 61 | boolean[] used = new boolean[p1.length()]; 62 | for (int k = 0; k < used.length; k++) { 63 | if (p1.get(k) == p2.get(k)) { 64 | used[p1.get(k)] = true; 65 | } 66 | } 67 | int i = 0; 68 | for (i = 0; i < used.length; i++) { 69 | if (!used[p1.get(i)]) { 70 | break; 71 | } 72 | } 73 | 74 | if (i >= used.length) { 75 | return 0; 76 | } else { 77 | int[] invP1 = p1.getInverse(); 78 | int iLast = i; 79 | 80 | int j = p1.get(i); 81 | while (!used[j]) { 82 | used[j] = true; 83 | j = p2.get(i); 84 | i = invP1[j]; 85 | } 86 | for (i = iLast + 1; i < used.length; i++) { 87 | if (!used[p1.get(i)]) { 88 | return 2; 89 | } 90 | } 91 | return 1; 92 | } 93 | } 94 | 95 | @Override 96 | public int max(int length) { 97 | return length >= 4 ? 2 : (length >= 2 ? 1 : 0); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/CyclicEdgeDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * Cyclic edge distance treats the permutations as if they represent sets of edges, and counts the 27 | * number of edges that differ. It treats the last to the first element as an edge. 28 | * 29 | *

Consider the example permutation: [1, 5, 2, 4, 0, 3]. Cyclic edge distance treats this as 30 | * equivalent to the set of undirected edges: {(1,5), (5,2), (2,4), (4,0), (0,3), (3,1)}. 31 | * 32 | *

E.g., distance between [1, 5, 2, 4, 0, 3] and [ 5, 1, 4, 0, 3, 2] is 3. Why? Well, the first 33 | * permutation has the edges: {(1,5), (5,2), (2,4), (4,0), (0,3), (3,1)}. The second has three of 34 | * these (5,1), which is the same as (1,5) since they are undirected edges, (4,0), and (0,3), but 35 | * does not include 3 of the edges: (5,2), (2,4), (3,1) 36 | * 37 | *

Runtime: O(n), where n is the permutation length. 38 | * 39 | *

Cyclic edge distance was first described in:
40 | * S. Ronald, "Distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 1997, 41 | * pp. 49–54. 42 | * 43 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 45 | */ 46 | public final class CyclicEdgeDistance implements NormalizedPermutationDistanceMeasurer { 47 | 48 | /** Constructs the distance measurer as specified in the class documentation. */ 49 | public CyclicEdgeDistance() {} 50 | 51 | /** 52 | * {@inheritDoc} 53 | * 54 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 55 | */ 56 | @Override 57 | public int distance(Permutation p1, Permutation p2) { 58 | if (p1.length() != p2.length()) { 59 | throw new IllegalArgumentException("Permutations must be the same length"); 60 | } 61 | int countNonSharedEdges = 0; 62 | int[] successors2 = new int[p2.length()]; 63 | for (int i = 0; i < successors2.length; i++) { 64 | successors2[p2.get(i)] = p2.get(indexCyclicAdjustment(i + 1, successors2.length)); 65 | } 66 | 67 | for (int i = 0; i < successors2.length; i++) { 68 | int j = indexCyclicAdjustment(i + 1, successors2.length); 69 | if (p1.get(j) != successors2[p1.get(i)] && p1.get(i) != successors2[p1.get(j)]) { 70 | countNonSharedEdges++; 71 | } 72 | } 73 | 74 | return countNonSharedEdges; 75 | } 76 | 77 | @Override 78 | public int max(int length) { 79 | if (length <= 3) return 0; 80 | if (length == 4) return 2; 81 | return length; 82 | } 83 | 84 | private int indexCyclicAdjustment(int i, int length) { 85 | return i < length ? i : 0; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/CyclicIndependentDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * This class implements the concept of a cyclic independent distance measure. This is relevant if 27 | * any rotation of the permutation has the same problem dependent interpretation. 28 | * 29 | *

In this case, this class computes the minimum of the distance from permutation p1 to rotations 30 | * of p2, where the underlying distance measure is passed as a parameter to the constructor. 31 | * 32 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 34 | */ 35 | public final class CyclicIndependentDistance implements PermutationDistanceMeasurer { 36 | 37 | private PermutationDistanceMeasurer d; 38 | 39 | /** 40 | * Constructs a distance measure for measuring distance with cyclic independence, such that 41 | * distance = min_{i in [0,N)} distance(p1,rotate(p2,i)) 42 | * 43 | * @param d A distance measure. 44 | */ 45 | public CyclicIndependentDistance(PermutationDistanceMeasurer d) { 46 | this.d = d; 47 | } 48 | 49 | /** 50 | * Measures the distance between two permutations, with cyclic independence: distance = min_{i in 51 | * [0,N)} distance(p1,rotate(p2,i)) 52 | * 53 | * @param p1 first permutation 54 | * @param p2 second permutation 55 | * @return distance between p1 and p2 56 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 57 | */ 58 | @Override 59 | public int distance(Permutation p1, Permutation p2) { 60 | int result = d.distance(p1, p2); 61 | Permutation pCopy = new Permutation(p2); 62 | int L = pCopy.length(); 63 | for (int i = 0; i < L && result > 0; i++) { 64 | pCopy.rotate(1); 65 | result = Math.min(result, d.distance(p1, pCopy)); 66 | } 67 | return result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/CyclicIndependentDistanceDouble.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * This class implements the concept of a cyclic independent distance measure. This is relevant if 27 | * any rotation of the permutation has the same problem dependent interpretation. 28 | * 29 | *

In this case, this class computes the minimum of the distance from permutation p1 to rotations 30 | * of p2, where the underlying distance measure is passed as a parameter to the constructor. 31 | * 32 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 34 | */ 35 | public final class CyclicIndependentDistanceDouble implements PermutationDistanceMeasurerDouble { 36 | 37 | private PermutationDistanceMeasurerDouble d; 38 | 39 | /** 40 | * Constructs a distance measure for measuring distance with cyclic independence, such that 41 | * distance = min_{i in [0,N)} distance(p1,rotate(p2,i)) 42 | * 43 | * @param d A distance measure. 44 | */ 45 | public CyclicIndependentDistanceDouble(PermutationDistanceMeasurerDouble d) { 46 | this.d = d; 47 | } 48 | 49 | /** 50 | * Measures the distance between two permutations, with cyclic independence: distance = min_{i in 51 | * [0,N)} distance(p1,rotate(p2,i)) 52 | * 53 | * @param p1 first permutation 54 | * @param p2 second permutation 55 | * @return distance between p1 and p2 56 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 57 | */ 58 | @Override 59 | public double distancef(Permutation p1, Permutation p2) { 60 | double result = d.distancef(p1, p2); 61 | Permutation pCopy = new Permutation(p2); 62 | int L = pCopy.length(); 63 | for (int i = 0; i < L && result > 0; i++) { 64 | pCopy.rotate(1); 65 | result = Math.min(result, d.distancef(p1, pCopy)); 66 | } 67 | return result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/CyclicRTypeDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * Cyclic RType distance treats the permutations as if they represent sets of directed edges, and 27 | * counts the number of edges that differ. It treats the last to the first element as an edge. 28 | * 29 | *

Consider the example permutation: [1, 5, 2, 4, 0, 3]. Cyclic RType distance treats this as 30 | * equivalent to the set of directed edges: {(1,5), (5,2), (2,4), (4,0), (0,3), (3,1)}. 31 | * 32 | *

E.g., distance between [1, 5, 2, 4, 0, 3] and [ 5, 1, 4, 0, 3, 2] is 4. Why? Well, the first 33 | * permutation has the directed edges: {(1,5), (5,2), (2,4), (4,0), (0,3), (3,1)}. The second has 2 34 | * of these (4,0), and (0,3), but does not include 4 of the edges: (1,5), (5,2), (2,4), (3,1) 35 | * 36 | *

Runtime: O(n), where n is the permutation length. 37 | * 38 | *

Cyclic RType distance was introduced in:
39 | * V.A. Cicirello, "The Permutation in a Haystack Problem and the Calculus of Search Landscapes," 41 | * IEEE Transactions on Evolutionary Computation, 20(3):434-446, June 2016. 42 | * 43 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 45 | */ 46 | public final class CyclicRTypeDistance implements NormalizedPermutationDistanceMeasurer { 47 | 48 | /** Constructs the distance measurer as specified in the class documentation. */ 49 | public CyclicRTypeDistance() {} 50 | 51 | /** 52 | * {@inheritDoc} 53 | * 54 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 55 | */ 56 | @Override 57 | public int distance(Permutation p1, Permutation p2) { 58 | if (p1.length() != p2.length()) { 59 | throw new IllegalArgumentException("Permutations must be the same length"); 60 | } 61 | int countNonSharedEdges = 0; 62 | int[] successors2 = new int[p2.length()]; 63 | for (int i = 0; i < successors2.length; i++) { 64 | successors2[p2.get(i)] = p2.get(indexCyclicAdjustment(i + 1, successors2.length)); 65 | } 66 | 67 | for (int i = 0; i < successors2.length; i++) { 68 | if (p1.get(indexCyclicAdjustment(i + 1, successors2.length)) != successors2[p1.get(i)]) { 69 | countNonSharedEdges++; 70 | } 71 | } 72 | return countNonSharedEdges; 73 | } 74 | 75 | @Override 76 | public int max(int length) { 77 | if (length <= 2) return 0; 78 | return length; 79 | } 80 | 81 | private int indexCyclicAdjustment(int i, int length) { 82 | return i < length ? i : 0; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/CyclicReversalIndependentDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * This class implements the combination of cyclic independence and reversal independence. This is 27 | * relevant if any rotation of the permutation or its reverse has the same problem dependent 28 | * interpretation. For example, if the permutation represents a solution to a traveling salesperson 29 | * problem (i.e. a tour of a set of cities), then the cost of that tour is the same if you rotate 30 | * it, reverse it, or reverse it and rotate it. 31 | * 32 | *

In this case, this class computes the minimum of the distance from permutation p1 to rotations 33 | * of p2 and rotations of the reverse of p2, where the underlying distance measure is passed as a 34 | * parameter to the constructor. 35 | * 36 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 38 | */ 39 | public final class CyclicReversalIndependentDistance implements PermutationDistanceMeasurer { 40 | 41 | private PermutationDistanceMeasurer d; 42 | 43 | /** 44 | * Constructs a distance measure for measuring distance with cyclic and reversal independence, 45 | * such that distance = min_{i in [0,N)} { distance(p1,rotate(p2,i)), 46 | * distance(p1,rotate(reverse(p2),i)) } 47 | * 48 | * @param d A distance measure. 49 | */ 50 | public CyclicReversalIndependentDistance(PermutationDistanceMeasurer d) { 51 | this.d = d; 52 | } 53 | 54 | /** 55 | * Measures the distance between two permutations, with cyclic and reversal independence: distance 56 | * = min_{i in [0,N)} { distance(p1,rotate(p2,i)), distance(p1,rotate(reverse(p2),i)) } 57 | * 58 | * @param p1 first permutation 59 | * @param p2 second permutation 60 | * @return distance between p1 and p2 61 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 62 | */ 63 | @Override 64 | public int distance(Permutation p1, Permutation p2) { 65 | int result = d.distance(p1, p2); 66 | if (result > 0) { 67 | Permutation reverse2 = new Permutation(p2); 68 | reverse2.reverse(); 69 | result = Math.min(result, d.distance(p1, reverse2)); 70 | if (result > 0) { 71 | int L = reverse2.length(); 72 | for (int i = 0; i < L && result > 0; i++) { 73 | reverse2.rotate(1); 74 | result = Math.min(result, d.distance(p1, reverse2)); 75 | } 76 | } 77 | if (result > 0) { 78 | Permutation pCopy = new Permutation(p2); 79 | int L = pCopy.length(); 80 | for (int i = 0; i < L && result > 0; i++) { 81 | pCopy.rotate(1); 82 | result = Math.min(result, d.distance(p1, pCopy)); 83 | } 84 | } 85 | } 86 | return result; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/CyclicReversalIndependentDistanceDouble.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * This class implements the combination of cyclic independence and reversal independence. This is 27 | * relevant if any rotation of the permutation or its reverse has the same problem dependent 28 | * interpretation. For example, if the permutation represents a solution to a traveling salesperson 29 | * problem (i.e. a tour of a set of cities), then the cost of that tour is the same if you rotate 30 | * it, reverse it, or reverse it and rotate it. 31 | * 32 | *

In this case, this class computes the minimum of the distance from permutation p1 to rotations 33 | * of p2 and rotations of the reverse of p2, where the underlying distance measure is passed as a 34 | * parameter to the constructor. 35 | * 36 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 38 | */ 39 | public final class CyclicReversalIndependentDistanceDouble 40 | implements PermutationDistanceMeasurerDouble { 41 | 42 | private PermutationDistanceMeasurerDouble d; 43 | 44 | /** 45 | * Constructs a distance measure for measuring distance with cyclic and reversal independence, 46 | * such that distance = min_{i in [0,N)} { distance(p1,rotate(p2,i)), 47 | * distance(p1,rotate(reverse(p2),i)) } 48 | * 49 | * @param d A distance measure. 50 | */ 51 | public CyclicReversalIndependentDistanceDouble(PermutationDistanceMeasurerDouble d) { 52 | this.d = d; 53 | } 54 | 55 | /** 56 | * Measures the distance between two permutations, with cyclic and reversal independence: distance 57 | * = min_{i in [0,N)} { distance(p1,rotate(p2,i)), distance(p1,rotate(reverse(p2),i)) } 58 | * 59 | * @param p1 first permutation 60 | * @param p2 second permutation 61 | * @return distance between p1 and p2 62 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 63 | */ 64 | @Override 65 | public double distancef(Permutation p1, Permutation p2) { 66 | double result = d.distancef(p1, p2); 67 | if (result > 0) { 68 | Permutation reverse2 = new Permutation(p2); 69 | reverse2.reverse(); 70 | result = Math.min(result, d.distancef(p1, reverse2)); 71 | if (result > 0) { 72 | int L = reverse2.length(); 73 | for (int i = 0; i < L && result > 0; i++) { 74 | reverse2.rotate(1); 75 | result = Math.min(result, d.distancef(p1, reverse2)); 76 | } 77 | } 78 | if (result > 0) { 79 | Permutation pCopy = new Permutation(p2); 80 | int L = pCopy.length(); 81 | for (int i = 0; i < L && result > 0; i++) { 82 | pCopy.rotate(1); 83 | result = Math.min(result, d.distancef(p1, pCopy)); 84 | } 85 | } 86 | } 87 | return result; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/DeviationDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * Deviation distance is the sum of the positional deviation of the permutation elements. The 27 | * positional deviation of an element is the difference in its location in the two permutations. 28 | * 29 | *

For example, consider p1 = [0, 1, 2, 3, 4, 5] and p2 = [1, 0, 5, 2, 4, 3]. Element 0 is 30 | * displaced by 1 position. Likewise for elements 1 and 2. Element 3 is displaced by 2 positions. 31 | * Element 4 is in the same position in both. Element 5 is displaced by 3 positions. 32 | * 33 | *

Sum the deviations: 1 + 1 + 1 + 2 + 0 + 3 = 8. And that is the distance. 34 | * 35 | *

Runtime: O(n), where n is the permutation length. 36 | * 37 | *

Deviation distance was introduced in:
38 | * S. Ronald, "More distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 39 | * 1998, pp. 558–563. 40 | * 41 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 43 | */ 44 | public final class DeviationDistance implements NormalizedPermutationDistanceMeasurer { 45 | 46 | /** Constructs the distance measurer as specified in the class documentation. */ 47 | public DeviationDistance() {} 48 | 49 | /** 50 | * {@inheritDoc} 51 | * 52 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 53 | */ 54 | @Override 55 | public int distance(Permutation p1, Permutation p2) { 56 | if (p1.length() != p2.length()) { 57 | throw new IllegalArgumentException("Permutations must be the same length"); 58 | } 59 | 60 | int distancePoints = 0; 61 | int[] invP2 = p2.getInverse(); 62 | 63 | for (int i = 0; i < invP2.length; i++) { 64 | distancePoints += Math.abs(invP2[p1.get(i)] - i); 65 | } 66 | return distancePoints; 67 | } 68 | 69 | @Override 70 | public int max(int length) { 71 | if (length <= 1) return 0; 72 | return (length * length - (length & 1)) >> 1; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/DeviationDistanceNormalized.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * Normalized Deviation distance is the sum of the positional deviation of the permutation elements 27 | * divided by N-1 (where N is the length of the permutation). The positional deviation of an element 28 | * is the difference in its location in the two permutations. Normalizing by dividing by N-1 causes 29 | * each element's contribution to distance to be in the interval [0,1]. 30 | * 31 | *

For example, consider p1 = [0, 1, 2, 3, 4, 5] and p2 = [1, 0, 5, 2, 4, 3]. Element 0 is 32 | * displaced by 1 position. Likewise for elements 1 and 2. Element 3 is displaced by 2 positions. 33 | * Element 4 is in the same position in both. Element 5 is displaced by 3 positions. 34 | * 35 | *

Sum the deviations: 1 + 1 + 1 + 2 + 0 + 3 = 8. 36 | * 37 | *

The length is 6. So, normalized deviation distance is 8 / (6-1) = 1.6. 38 | * 39 | *

Runtime: O(n), where n is the permutation length. 40 | * 41 | *

Normalized deviation distance was introduced in:
42 | * S. Ronald, "More distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 43 | * 1998, pp. 558–563. 44 | * 45 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 47 | */ 48 | public final class DeviationDistanceNormalized 49 | implements NormalizedPermutationDistanceMeasurerDouble { 50 | 51 | private DeviationDistance devDistance; 52 | 53 | /** Constructs the distance measurer as specified in the class documentation. */ 54 | public DeviationDistanceNormalized() { 55 | devDistance = new DeviationDistance(); 56 | } 57 | 58 | /** 59 | * {@inheritDoc} 60 | * 61 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 62 | */ 63 | @Override 64 | public double distancef(Permutation p1, Permutation p2) { 65 | if (p1.length() != p2.length()) { 66 | throw new IllegalArgumentException("Permutations must be the same length"); 67 | } 68 | if (p1.length() <= 1) return 0; 69 | return devDistance.distancef(p1, p2) / (p1.length() - 1); 70 | } 71 | 72 | @Override 73 | public double maxf(int length) { 74 | if (length <= 1) return 0; 75 | return (length * length - (length & 1)) / (2.0 * (length - 1)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/DeviationDistanceNormalized2005.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * The original version of Normalized Deviation distance (Ronald, 1998) is the sum of the positional 27 | * deviation of the permutation elements divided by N-1 (where N is the length of the permutation). 28 | * The positional deviation of an element is the difference in its location in the two permutations. 29 | * Normalizing by dividing by N-1 causes each element's contribution to distance to be in the 30 | * interval [0,1]. 31 | * 32 | *

Sevaux and Sorensen (2005) suggested a different normalizing factor that provides a distance 33 | * in the interval [0,1]. Maximal distance occurs for an inverted permutation. The normalizing 34 | * factor is (N2/2) when N is even and (N2-1)/2 when N is odd. 35 | * 36 | *

For example, consider p1 = [0, 1, 2, 3, 4, 5] and p2 = [1, 0, 5, 2, 4, 3]. Element 0 is 37 | * displaced by 1 position. Likewise for elements 1 and 2. Element 3 is displaced by 2 positions. 38 | * Element 4 is in the same position in both. Element 5 is displaced by 3 positions. 39 | * 40 | *

Sum the deviations: 1 + 1 + 1 + 2 + 0 + 3 = 8. 41 | * 42 | *

The length is 6, which is even, so we'll divide by 18. So, normalized deviation distance is 8 43 | * / 18 = 0.444... 44 | * 45 | *

If instead, p2 = [5, 4, 3, 2, 1, 0], then 0 and 5 are both displaced by 5 positions, 1 and 4 46 | * are displaced by 3 positions, and 2 and 3 are displaced by 1 position. Sum of deviations is then: 47 | * 2 * 5 + 2 * 3 + 2 * 1 = 18. The length is still 6, so we again divide by 18, and distance is 1. 48 | * 49 | *

Runtime: O(n), where n is the permutation length. 50 | * 51 | *

Original normalized deviation distance was introduced in:
52 | * S. Ronald, "More distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 53 | * 1998, pp. 558–563. 54 | * 55 | *

This version of normalized deviation distance was introduced in:
56 | * M. Sevaux and K Sorensen, "Permutation distance measures for memetic algorithms with population 57 | * management," in Proc. of MIC2005, 2005. 58 | * 59 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 61 | */ 62 | public final class DeviationDistanceNormalized2005 63 | implements NormalizedPermutationDistanceMeasurerDouble { 64 | 65 | private DeviationDistance devDistance; 66 | 67 | /** Constructs the distance measurer as specified in the class documentation. */ 68 | public DeviationDistanceNormalized2005() { 69 | devDistance = new DeviationDistance(); 70 | } 71 | 72 | /** 73 | * {@inheritDoc} 74 | * 75 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 76 | */ 77 | @Override 78 | public double distancef(Permutation p1, Permutation p2) { 79 | if (p1.length() != p2.length()) { 80 | throw new IllegalArgumentException("Permutations must be the same length"); 81 | } 82 | if (p1.length() <= 1) return 0; 83 | return devDistance.distancef(p1, p2) * 2.0 / (p1.length() * p1.length() - (p1.length() & 1)); 84 | } 85 | 86 | @Override 87 | public double maxf(int length) { 88 | if (length <= 1) return 0; 89 | return 1.0; 90 | } 91 | 92 | /** 93 | * {@inheritDoc} 94 | * 95 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 96 | */ 97 | @Override 98 | public double normalizedDistance(Permutation p1, Permutation p2) { 99 | return distancef(p1, p2); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/ExactMatchDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * Exact Match distance is an extension of Hamming distance but to non-binary strings, in this case, 27 | * permutations. It is the count of the number of positions for which the two permutations contain 28 | * different elements. 29 | * 30 | *

Runtime: O(n), where n is the permutation length. 31 | * 32 | *

Exact match distance was introduced in:
33 | * S. Ronald, "More distance functions for order-based encodings," in Proc. IEEE CEC. IEEE Press, 34 | * 1998, pp. 558–563. 35 | * 36 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 38 | */ 39 | public final class ExactMatchDistance implements NormalizedPermutationDistanceMeasurer { 40 | 41 | /** Constructs the distance measurer as specified in the class documentation. */ 42 | public ExactMatchDistance() {} 43 | 44 | /** 45 | * {@inheritDoc} 46 | * 47 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 48 | */ 49 | @Override 50 | public int distance(Permutation p1, Permutation p2) { 51 | if (p1.length() != p2.length()) { 52 | throw new IllegalArgumentException("Permutations must be the same length"); 53 | } 54 | int misMatchPoints = 0; 55 | for (int i = 0; i < p1.length(); i++) { 56 | if (p1.get(i) != p2.get(i)) { 57 | misMatchPoints++; 58 | } 59 | } 60 | return misMatchPoints; 61 | } 62 | 63 | @Override 64 | public int max(int length) { 65 | if (length <= 1) return 0; 66 | return length; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/InterchangeDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools - A Java library for computation on permutations. 3 | * Copyright 2005-2024 Vincent A. Cicirello, . 4 | * 5 | * JavaPermutationTools is free software: you can 6 | * redistribute it and/or modify it under the terms of the GNU 7 | * General Public License as published by the Free Software 8 | * Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * JavaPermutationTools is distributed in the hope 12 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 13 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | * PARTICULAR PURPOSE. See the GNU General Public License for more 15 | * details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with JavaPermutationTools. If not, see . 19 | * 20 | */ 21 | package org.cicirello.permutations.distance; 22 | 23 | import org.cicirello.permutations.Permutation; 24 | 25 | /** 26 | * Interchange distance is the minimum number of swaps necessary to transform one permutation into 27 | * the other. 28 | * 29 | *

Interchange distance is computed efficiently by counting the number of permutation cycles 30 | * between the permutations. A permutation cycle of length k is transformed into k fixed points with 31 | * k - 1 swaps (a fixed point is a cycle of length 1). 32 | * 33 | *

Runtime: O(n), where n is the permutation length. 34 | * 35 | *

Computing Interchange distance using cycle lengths is described in:
36 | * V.A. Cicirello, "The Permutation in a Haystack Problem and the Calculus of Search Landscapes," 38 | * IEEE Transactions on Evolutionary Computation, 20(3):434-446, June 2016. 39 | * 40 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 42 | */ 43 | public final class InterchangeDistance implements NormalizedPermutationDistanceMeasurer { 44 | 45 | /** Constructs the distance measurer as specified in the class documentation. */ 46 | public InterchangeDistance() {} 47 | 48 | /** 49 | * {@inheritDoc} 50 | * 51 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 52 | */ 53 | @Override 54 | public int distance(Permutation p1, Permutation p2) { 55 | if (p1.length() != p2.length()) { 56 | throw new IllegalArgumentException("Permutations must be the same length"); 57 | } 58 | int numSwaps = 0; 59 | int length = p1.length(); 60 | boolean[] used = new boolean[length]; 61 | for (int k = 0; k < length; k++) { 62 | if (p1.get(k) == p2.get(k)) used[p1.get(k)] = true; 63 | } 64 | int i = 0; 65 | for (i = 0; i < used.length; i++) { 66 | if (!used[p1.get(i)]) { 67 | break; 68 | } 69 | } 70 | if (i >= used.length) return 0; 71 | int iLast = i; 72 | 73 | int[] invP1 = p1.getInverse(); 74 | boolean done = true; 75 | do { 76 | done = true; 77 | int cycleSize = 0; 78 | int j = p1.get(i); 79 | while (!used[j]) { 80 | used[j] = true; 81 | cycleSize++; 82 | j = p2.get(i); 83 | i = invP1[j]; 84 | } 85 | numSwaps += (cycleSize - 1); 86 | for (i = iLast + 1; i < used.length; i++) { 87 | if (!used[p1.get(i)]) { 88 | done = false; 89 | break; 90 | } 91 | } 92 | iLast = i; 93 | } while (!done); 94 | return numSwaps; 95 | } 96 | 97 | @Override 98 | public int max(int length) { 99 | if (length <= 1) return 0; 100 | return length - 1; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/KCycleDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * K-Cycle distance is the count of the number of non-singleton permutation cycles of length at most 28 | * K. Specifically, each non-singleton cycle contributes to the total distance the number of cycles 29 | * of length at most K necessary to transform the cycle to all fixed points. K-cycle distance is a 30 | * metric provided that K ≤ 4. However, if K > 4, it is only a semi-metric because it fails to 31 | * satisfy the triangle inequality when K ≥ 5. 32 | * 33 | *

K-Cycle distance was introduced in the following article: 34 | * 35 | *

Vincent A. Cicirello. 2022. Cycle Mutation: Evolving 37 | * Permutations via Cycle Induction, Applied Sciences, 12(11), Article 5506 (June 2022). 38 | * doi:10.3390/app12115506 39 | * 40 | *

Runtime: O(n), where n is the permutation length. 41 | * 42 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 44 | */ 45 | public final class KCycleDistance implements NormalizedPermutationDistanceMeasurer { 46 | 47 | private final int maxCycleLength; 48 | 49 | private int lastLength; 50 | private int precomputedMax; 51 | 52 | /** 53 | * Constructs the distance measurer as specified in the class documentation. 54 | * 55 | * @param k The maximum length cycle that is considered an atomic edit operation, such that k is 56 | * greater than or equal to 2. 57 | * @throws IllegalArgumentException if k is less than 2 58 | */ 59 | public KCycleDistance(int k) { 60 | if (k < 2) { 61 | throw new IllegalArgumentException("k must be at least 2"); 62 | } 63 | this.maxCycleLength = k; 64 | } 65 | 66 | /** 67 | * {@inheritDoc} 68 | * 69 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 70 | */ 71 | @Override 72 | public int distance(Permutation p1, Permutation p2) { 73 | if (p1.length() != p2.length()) { 74 | throw new IllegalArgumentException("Permutations must be the same length"); 75 | } 76 | boolean[] used = new boolean[p1.length()]; 77 | for (int k = 0; k < used.length; k++) { 78 | if (p1.get(k) == p2.get(k)) { 79 | used[p1.get(k)] = true; 80 | } 81 | } 82 | int i = 0; 83 | for (i = 0; i < used.length; i++) { 84 | if (!used[p1.get(i)]) { 85 | break; 86 | } 87 | } 88 | 89 | int[] invP1 = p1.getInverse(); 90 | int cycleCount = 0; 91 | int iLast = i; 92 | 93 | while (i < used.length) { 94 | int j = p1.get(i); 95 | int cycleLength = 0; 96 | while (!used[j]) { 97 | used[j] = true; 98 | cycleLength++; 99 | j = p2.get(i); 100 | i = invP1[j]; 101 | } 102 | 103 | if (cycleLength > maxCycleLength) { 104 | cycleCount += (int) Math.ceil((cycleLength - 1.0) / (maxCycleLength - 1.0)); 105 | } else { 106 | cycleCount++; 107 | } 108 | 109 | for (i = iLast + 1; i < used.length; i++) { 110 | if (!used[p1.get(i)]) { 111 | break; 112 | } 113 | } 114 | iLast = i; 115 | } 116 | return cycleCount; 117 | } 118 | 119 | @Override 120 | public int max(int length) { 121 | if (length != lastLength) { 122 | lastLength = length; 123 | precomputedMax = 124 | Math.max(length >> 1, (int) Math.ceil((length - 1.0) / (maxCycleLength - 1.0))); 125 | } 126 | return precomputedMax; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/LeeDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Lee Distance is closely related to deviation distance. However, Lee Distance considers the 28 | * permutation to be a cyclic structure when computing positional deviations. That is, an element's 29 | * deviation between permutations is the minimum of its deviation to the right or to the left 30 | * (wrapping around ends cyclicly). 31 | * 32 | *

Consider p1 = [0, 1, 2, 3, 4, 5] and p2 = [5, 1, 0, 2, 3, 4]. Element 0 is 2 positions 33 | * displaced (as in deviation distance). Elements 2, 3, and 4 are a 1 position displaced (as in 34 | * deviation distance). Element 1 is stationary. Element 5 is 1 position displaced (for Lee 35 | * Distance) whereas for Deviation Distance it would be 5 positions displaced. For Lee distance, the 36 | * displacement is the minimum of how far it is displaced in either of the two directions. In this 37 | * case element 5 is at the right most end in p1 and left most end of p2, which as a cyclic 38 | * structure are adjacent positions. 39 | * 40 | *

Runtime: O(n), where n is the permutation length. 41 | * 42 | *

Described in:
43 | * C. Lee, "Some properties of nonbinary error-correcting codes," in IRE Transactions on Information 44 | * Theory, vol. 4, no. 2, pp. 77-82, June 1958. 45 | * 46 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 48 | */ 49 | public final class LeeDistance implements NormalizedPermutationDistanceMeasurer { 50 | 51 | /** Constructs the distance measurer as specified in the class documentation. */ 52 | public LeeDistance() {} 53 | 54 | /** 55 | * {@inheritDoc} 56 | * 57 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 58 | */ 59 | @Override 60 | public int distance(Permutation p1, Permutation p2) { 61 | if (p1.length() != p2.length()) { 62 | throw new IllegalArgumentException("Permutations must be the same length"); 63 | } 64 | if (p1.length() <= 1) return 0; 65 | int distancePoints = 0; 66 | int[] invP1 = p1.getInverse(); 67 | int[] invP2 = p2.getInverse(); 68 | 69 | for (int i = 0; i < invP1.length; i++) { 70 | int dev = Math.abs(invP1[i] - invP2[i]); 71 | distancePoints += Math.min(dev, invP1.length - dev); 72 | } 73 | 74 | return distancePoints; 75 | } 76 | 77 | @Override 78 | public int max(int length) { 79 | if (length <= 1) return 0; 80 | return length * (length >> 1); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Implement this interface to define a distance metric for permutations that supports normalizing 28 | * the distance to the interval [0,1], but where the base distance is an integer value. 29 | * 30 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 32 | */ 33 | public interface NormalizedPermutationDistanceMeasurer 34 | extends NormalizedPermutationDistanceMeasurerDouble, PermutationDistanceMeasurer { 35 | 36 | /** 37 | * Computes the maximum possible distance between permutations of a specified length. 38 | * 39 | * @param length Permutation length. 40 | * @return the maximum distance between a pair of permutations of the specified length. 41 | */ 42 | int max(int length); 43 | 44 | @Override 45 | default double maxf(int length) { 46 | return max(length); 47 | } 48 | 49 | /** 50 | * {@inheritDoc} 51 | * 52 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 53 | */ 54 | @Override 55 | default double normalizedDistance(Permutation p1, Permutation p2) { 56 | int m = max(p1.length()); 57 | if (m == 0) return 0; 58 | return distance(p1, p2) / ((double) m); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/NormalizedPermutationDistanceMeasurerDouble.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Implement this interface to define a distance metric for permutations that supports normalizing 28 | * the distance to the interval [0,1]. 29 | * 30 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 32 | */ 33 | public interface NormalizedPermutationDistanceMeasurerDouble 34 | extends PermutationDistanceMeasurerDouble { 35 | 36 | /** 37 | * Computes the maximum possible distance between permutations of a specified length. 38 | * 39 | * @param length Permutation length. 40 | * @return the maximum distance between a pair of permutations of the specified length. 41 | */ 42 | double maxf(int length); 43 | 44 | /** 45 | * Measures the distance between two permutations, normalized to the interval [0.0, 1.0]. 46 | * 47 | * @param p1 first permutation 48 | * @param p2 second permutation 49 | * @return distance between p1 and p2 normalized to the interval [0.0, 1.0] 50 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 51 | */ 52 | default double normalizedDistance(Permutation p1, Permutation p2) { 53 | double m = maxf(p1.length()); 54 | if (m == 0) return 0; 55 | return distancef(p1, p2) / m; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/PermutationDistanceMeasurer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Implement this interface, PermutationDistanceMeasurer, to define a distance metric for 28 | * permutations. 29 | * 30 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 32 | */ 33 | public interface PermutationDistanceMeasurer extends PermutationDistanceMeasurerDouble { 34 | /** 35 | * Measures the distance between two permutations. 36 | * 37 | * @param p1 first permutation 38 | * @param p2 second permutation 39 | * @return distance between p1 and p2 40 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 41 | */ 42 | int distance(Permutation p1, Permutation p2); 43 | 44 | /** 45 | * {@inheritDoc} 46 | * 47 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 48 | */ 49 | @Override 50 | default double distancef(Permutation p1, Permutation p2) { 51 | return distance(p1, p2); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/PermutationDistanceMeasurerDouble.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Implement this interface, PermutationDistanceMeasurerDouble, to define a distance metric for 28 | * permutations, where the distance is a floating-point value. 29 | * 30 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 32 | */ 33 | public interface PermutationDistanceMeasurerDouble { 34 | /** 35 | * Measures the distance between two permutations 36 | * 37 | * @param p1 first permutation 38 | * @param p2 second permutation 39 | * @return distance between p1 and p2 40 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 41 | */ 42 | double distancef(Permutation p1, Permutation p2); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/RTypeDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * RType distance treats the permutations as if they represent sets of directed edges, and counts 28 | * the number of edges that differ. 29 | * 30 | *

Consider the example permutation: [1, 5, 2, 4, 0, 3]. RType distance treats this as equivalent 31 | * to the set of directed edges: {(1,5), (5,2), (2,4), (4,0), (0,3)}. 32 | * 33 | *

E.g., distance between [1, 5, 2, 4, 0, 3] and [ 5, 1, 4, 0, 3, 2] is 3. Why? Well, the first 34 | * permutation has the directed edges: {(1,5), (5,2), (2,4), (4,0), (0,3)}. The second has 2 of 35 | * these (4,0), and (0,3), but does not include 3 of the edges: (1,5), (5,2), (2,4) 36 | * 37 | *

Runtime: O(n), where n is the permutation length. 38 | * 39 | *

RType distance was introduced in:
40 | * V. Campos, M. Laguna, and R. Marti, "Context-independent scatter and tabu search for permutation 41 | * problems," INFORMS Journal on Computing, vol. 17, no. 1, pp. 111–122, 2005. 42 | * 43 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 45 | */ 46 | public final class RTypeDistance implements NormalizedPermutationDistanceMeasurer { 47 | 48 | /** Constructs the distance measurer as specified in the class documentation. */ 49 | public RTypeDistance() {} 50 | 51 | /** 52 | * {@inheritDoc} 53 | * 54 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 55 | */ 56 | @Override 57 | public int distance(Permutation p1, Permutation p2) { 58 | if (p1.length() != p2.length()) { 59 | throw new IllegalArgumentException("Permutations must be the same length"); 60 | } 61 | int countNonSharedEdges = 0; 62 | if (p2.length() == 0) return 0; 63 | int[] successors2 = new int[p2.length()]; 64 | for (int i = 0; i < successors2.length - 1; i++) { 65 | successors2[p2.get(i)] = p2.get(i + 1); 66 | } 67 | successors2[p2.get(successors2.length - 1)] = -1; 68 | 69 | for (int i = 0; i < successors2.length - 1; i++) { 70 | if (p1.get(i + 1) != successors2[p1.get(i)]) countNonSharedEdges++; 71 | } 72 | return countNonSharedEdges; 73 | } 74 | 75 | @Override 76 | public int max(int length) { 77 | if (length <= 1) return 0; 78 | return length - 1; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/ReversalIndependentDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * This class implements the concept of a reversal independent distance measure. This is relevant if 28 | * the permutation and its reverse have the same problem dependent interpretation. 29 | * 30 | *

In this case, this class computes the minimum of distance(p1,p2) and distance(p1,reverse(p2)) 31 | * for a given distance measure passed as a parameter to the constructor. 32 | * 33 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 35 | */ 36 | public final class ReversalIndependentDistance implements PermutationDistanceMeasurer { 37 | 38 | private PermutationDistanceMeasurer d; 39 | 40 | /** 41 | * Constructs a distance measure for measuring distance with reversal independence, such that 42 | * distance = min { distance(p1,p2), distance(p1,reverse(p2)) } 43 | * 44 | * @param d A distance measure. 45 | */ 46 | public ReversalIndependentDistance(PermutationDistanceMeasurer d) { 47 | this.d = d; 48 | } 49 | 50 | /** 51 | * Measures the distance between two permutations, with reversal independence: distance = min { 52 | * distance(p1,p2), distance(p1,reverse(p2)) } 53 | * 54 | * @param p1 first permutation 55 | * @param p2 second permutation 56 | * @return distance between p1 and p2 57 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 58 | */ 59 | @Override 60 | public int distance(Permutation p1, Permutation p2) { 61 | int result = d.distance(p1, p2); 62 | if (result > 0) { 63 | Permutation pCopy = new Permutation(p2); 64 | pCopy.reverse(); 65 | result = Math.min(result, d.distance(p1, pCopy)); 66 | } 67 | return result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/ReversalIndependentDistanceDouble.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * This class implements the concept of a reversal independent distance measure. This is relevant if 28 | * the permutation and its reverse have the same problem dependent interpretation. 29 | * 30 | *

In this case, this class computes the minimum of distance(p1,p2) and distance(p1,reverse(p2)) 31 | * for a given distance measure passed as a parameter to the constructor. 32 | * 33 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 35 | */ 36 | public final class ReversalIndependentDistanceDouble implements PermutationDistanceMeasurerDouble { 37 | 38 | private PermutationDistanceMeasurerDouble d; 39 | 40 | /** 41 | * Constructs a distance measure for measuring distance with reversal independence, such that 42 | * distance = min { distance(p1,p2), distance(p1,reverse(p2)) } 43 | * 44 | * @param d A distance measure. 45 | */ 46 | public ReversalIndependentDistanceDouble(PermutationDistanceMeasurerDouble d) { 47 | this.d = d; 48 | } 49 | 50 | /** 51 | * Measures the distance between two permutations, with reversal independence: distance = min { 52 | * distance(p1,p2), distance(p1,reverse(p2)) } 53 | * 54 | * @param p1 first permutation 55 | * @param p2 second permutation 56 | * @return distance between p1 and p2 57 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 58 | */ 59 | @Override 60 | public double distancef(Permutation p1, Permutation p2) { 61 | double result = d.distancef(p1, p2); 62 | if (result > 0) { 63 | Permutation pCopy = new Permutation(p2); 64 | pCopy.reverse(); 65 | result = Math.min(result, d.distancef(p1, pCopy)); 66 | } 67 | return result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/ScrambleDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Scramble Distance is the minimum number of random shufflings needed to transform one permutation 28 | * into the other. This was implemented for a very specific purpose, and unlikely to be subsequently 29 | * useful. 30 | * 31 | *

The scramble distance is 0 if permutation p1 is identical to p2. Otherwise, scramble distance 32 | * is 1. 33 | * 34 | *

Runtime: O(n), where n is the permutation length. 35 | * 36 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 38 | */ 39 | public final class ScrambleDistance implements NormalizedPermutationDistanceMeasurer { 40 | 41 | /** Constructs the distance measurer as specified in the class documentation. */ 42 | public ScrambleDistance() {} 43 | 44 | @Override 45 | public int distance(Permutation p1, Permutation p2) { 46 | if (p1.equals(p2)) return 0; 47 | else return 1; 48 | } 49 | 50 | @Override 51 | public int max(int length) { 52 | if (length <= 1) return 0; 53 | return 1; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/SquaredDeviationDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import org.cicirello.permutations.Permutation; 25 | 26 | /** 27 | * Squared Deviation distance is the sum of the squares of the positional deviations of the 28 | * permutation elements. The positional deviation of an element is the difference in its location in 29 | * the two permutations. 30 | * 31 | *

For example, consider p1 = [0, 1, 2, 3, 4, 5] and p2 = [1, 0, 5, 2, 4, 3]. Element 0 is 32 | * displaced by 1 position. Likewise for elements 1 and 2. Element 3 is displaced by 2 positions. 33 | * Element 4 is in the same position in both. Element 5 is displaced by 3 positions. 34 | * 35 | *

Sum the squared deviations: 1^2 + 1^2 + 1^2 + 2^2 + 0^2 + 3^2 = 1 + 1 + 1 + 4 + 9 = 16. 36 | * 37 | *

Runtime: O(n), where n is the permutation length. 38 | * 39 | *

Squared deviation distance is described in:
40 | * M. Sevaux and K. Sorensen, "Permutation distance measures for memetic algorithms with population 41 | * management," The 6th Metaheuristics International Conference, August, 2005. 42 | * 43 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 45 | */ 46 | public final class SquaredDeviationDistance implements NormalizedPermutationDistanceMeasurer { 47 | 48 | /** Constructs the distance measurer as specified in the class documentation. */ 49 | public SquaredDeviationDistance() {} 50 | 51 | /** 52 | * {@inheritDoc} 53 | * 54 | * @throws IllegalArgumentException if p1.length() is not equal to p2.length(). 55 | */ 56 | @Override 57 | public int distance(Permutation p1, Permutation p2) { 58 | if (p1.length() != p2.length()) { 59 | throw new IllegalArgumentException("Permutations must be the same length"); 60 | } 61 | int distancePoints = 0; 62 | 63 | int[] invP2 = p2.getInverse(); 64 | 65 | for (int i = 0; i < invP2.length; i++) { 66 | int dev = invP2[p1.get(i)] - i; 67 | distancePoints += (dev * dev); 68 | } 69 | return distancePoints; 70 | } 71 | 72 | @Override 73 | public int max(int length) { 74 | if (length <= 1) return 0; 75 | return (length * length * length - length) / 3; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/distance/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | 23 | /** 24 | * Implementations of a variety of permutation distance measures. 25 | * 26 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 28 | */ 29 | package org.cicirello.permutations.distance; 30 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/permutations/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | 23 | /** 24 | * Collection of classes related to representing and manipulating permutations. 25 | * 26 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 28 | */ 29 | package org.cicirello.permutations; 30 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/sequences/SequenceSamplerUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.sequences; 23 | 24 | import java.lang.reflect.Array; 25 | 26 | /** 27 | * SequenceSamplerUtils is an internal utility class with utility methods related to efficiently 28 | * generating random samples of array elements, without replacement. 29 | * 30 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 32 | */ 33 | class SequenceSamplerUtils { 34 | 35 | /** prevent instantiation with a private constructor. */ 36 | private SequenceSamplerUtils() {} 37 | 38 | static void validateK(int k, int sourceLength) { 39 | if (k > sourceLength) { 40 | throw new IllegalArgumentException("k must be no greater than length of source array"); 41 | } 42 | } 43 | 44 | @SuppressWarnings("unchecked") 45 | static T[] allocateIfNecessary(T[] source, int k, T[] target) { 46 | if (target == null) { 47 | target = (T[]) Array.newInstance(source.getClass().getComponentType(), k); 48 | } else if (target.length < k) { 49 | target = (T[]) Array.newInstance(target.getClass().getComponentType(), k); 50 | } 51 | return target; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/sequences/distance/LongestCommonSubsequenceDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.sequences.distance; 23 | 24 | /** 25 | * LongestCommonSubsequenceDistance is a form of EditDistance, where the edit operations are limited 26 | * to deletions and insertions (i.e., no replacements or changes), and where the cost of an edit 27 | * operation is simply 1. It is the minimum number of element insertions and deletions necessary to 28 | * transform one sequence into the other. It can be computed as: N + M - 2 * lcs(s1, s2), where 29 | * lcs(s1, s2) is the length of the longest common subsequence of sequences s1 and s2, and N and M 30 | * are the lengths of s1 and s2 (see section 5 of Wagner and Fischer (1974)). 31 | * 32 | *

This class supports computing distance for Java String objects or arrays of any of the 33 | * primitive types, or arrays of objects. It makes no assumptions about the contents of the Strings 34 | * or arrays, and they can contain duplicates, or can be such that some elements only appear in one 35 | * or the other of the sequences, or can be of different lengths. 36 | * 37 | *

Runtime: O(n*m), where n and m are the lengths of the two sequences (i.e., Strings or arrays). 38 | * 39 | *

If you need to compute this distance for permutations (i.e., same length, same set of 40 | * elements, unique elements), then it is recommended to instead use the {@link 41 | * org.cicirello.permutations.distance.ReinsertionDistance} class. That class exploits the common 42 | * length, common set of elements, and unique elements properties of permutations to more 43 | * efficiently (in O(n lg n) time) compute the longest common subpermutation (i.e., that class does 44 | * not delegate the work to the edit distance algorithm). However, the result of ReinsertionDistance 45 | * is half of what LongestCommonSubsequenceDistance would compute. This is because for permutations 46 | * the elements that would be inserted are exactly the same as those that would be deleted by the 47 | * edit operations, and ReinsertionDistance is defined as an edit distance with one edit operation, 48 | * removal/reinsertion (i.e., a deletion is only half the operation, and the insertion is the other 49 | * half of the operation). 50 | * 51 | *

Wagner and Fischer's String Edit Distance was introduced in:
52 | * R. A. Wagner and M. J. Fischer, "The string-to-string correction problem," Journal of the ACM, 53 | * vol. 21, no. 1, pp. 168–173, January 1974. 54 | * 55 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 57 | */ 58 | public final class LongestCommonSubsequenceDistance extends EditDistance { 59 | 60 | /** Constructs a longest common subsequence distance. */ 61 | public LongestCommonSubsequenceDistance() { 62 | // Wagner and Fischer (1974) showed that this distance measure is equivalent to edit distance 63 | // with costs of 1 for each of deletes and insertions, and a cost of 2 (or greater) for changes. 64 | super(1, 1, 2); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/sequences/distance/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | 23 | /** 24 | * Implementations of distance measures for general sequences of various forms, including Strings, 25 | * arrays of primitive types, arrays of objects, etc. 26 | * 27 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 29 | */ 30 | package org.cicirello.sequences.distance; 31 | -------------------------------------------------------------------------------- /src/main/java/org/cicirello/sequences/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2022 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | 23 | /** 24 | * Classes that perform a variety of operations on sequences (such as arrays, etc). 25 | * 26 | * @author Vincent A. Cicirello, https://www.cicirello.org/ 28 | */ 29 | package org.cicirello.sequences; 30 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/PermutationInverseTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.junit.jupiter.api.*; 27 | 28 | /** JUnit tests for inverting a Permutation. */ 29 | public class PermutationInverseTests { 30 | 31 | @Test 32 | public void testGetInverse0() { 33 | Permutation p1 = new Permutation(0); 34 | assertEquals( 35 | 0, p1.getInverse().length, "length of inverse of zero length permutation should be 0"); 36 | } 37 | 38 | @Test 39 | public void testGetInverse() { 40 | int[] before = {4, 2, 5, 0, 3, 1}; 41 | int[] beforeCopy = before.clone(); 42 | Permutation p = new Permutation(before); 43 | int[] expected = {3, 5, 1, 4, 0, 2}; 44 | int[] inv = p.getInverse(); 45 | assertArrayEquals(expected, inv); 46 | assertArrayEquals(beforeCopy, before); 47 | int[] array = {0, 1, 2, 3, 4, 5}; 48 | p = new Permutation(array); 49 | assertArrayEquals(array, p.getInverse()); 50 | } 51 | 52 | @Test 53 | public void testGetInversePermutation() { 54 | int[] before = {4, 2, 5, 0, 3, 1}; 55 | Permutation p = new Permutation(before); 56 | Permutation p2 = new Permutation(before); 57 | int[] expected = {3, 5, 1, 4, 0, 2}; 58 | Permutation pExpected = new Permutation(expected); 59 | Permutation inv = p.getInversePermutation(); 60 | assertEquals(pExpected, inv); 61 | assertEquals(p2, p); 62 | int[] array = {0, 1, 2, 3, 4, 5}; 63 | p = new Permutation(array); 64 | assertEquals(p, p.getInversePermutation()); 65 | } 66 | 67 | @Test 68 | public void testInvert() { 69 | int[] before = {4, 2, 5, 0, 3, 1}; 70 | Permutation p = new Permutation(before); 71 | int oldHash = p.hashCode(); 72 | int[] expected = {3, 5, 1, 4, 0, 2}; 73 | Permutation pExpected = new Permutation(expected); 74 | p.invert(); 75 | assertEquals(pExpected, p); 76 | assertEquals(pExpected.hashCode(), p.hashCode()); 77 | assertNotEquals(oldHash, p.hashCode()); 78 | int[] array = {0, 1, 2, 3, 4, 5}; 79 | p = new Permutation(array); 80 | pExpected = new Permutation(array); 81 | assertEquals(pExpected.hashCode(), p.hashCode()); 82 | p.invert(); 83 | assertEquals(pExpected, p); 84 | assertEquals(pExpected.hashCode(), p.hashCode()); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/PermutationIteratorTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import java.util.NoSuchElementException; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for the PermutationIterator. */ 30 | public class PermutationIteratorTests { 31 | 32 | @Test 33 | public void testPermutationIterator() { 34 | int fact = 1; 35 | for (int n = 1; n <= 5; n++) { 36 | Permutation p = new Permutation(n); 37 | boolean checkedFirst = false; 38 | fact *= n; 39 | boolean[] found = new boolean[fact]; 40 | int count = 0; 41 | for (Permutation pPrime : p) { 42 | if (!checkedFirst) { 43 | assertEquals(p, pPrime); 44 | checkedFirst = true; 45 | } 46 | int permID = pPrime.toInteger(); 47 | assertFalse(found[permID]); 48 | found[permID] = true; 49 | count++; 50 | } 51 | assertEquals(fact, count); 52 | } 53 | final PermutationIterator iter = new PermutationIterator(4); 54 | fact = 24; 55 | boolean[] found = new boolean[fact]; 56 | int count = 0; 57 | while (iter.hasNext()) { 58 | Permutation p = iter.next(); 59 | int permID = p.toInteger(); 60 | assertFalse(found[permID]); 61 | found[permID] = true; 62 | count++; 63 | } 64 | assertEquals(fact, count); 65 | NoSuchElementException thrown = assertThrows(NoSuchElementException.class, () -> iter.next()); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/PermutationRemoveInsertTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import java.util.SplittableRandom; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for removing and reinserting. */ 30 | public class PermutationRemoveInsertTests { 31 | 32 | @Test 33 | public void testPermutationRemoveInsert() { 34 | Permutation p = new Permutation(5, new SplittableRandom(42)); 35 | for (int i = 0; i < p.length(); i++) { 36 | for (int j = 0; j < p.length(); j++) { 37 | Permutation copy = new Permutation(p); 38 | assertEquals(p.hashCode(), copy.hashCode()); 39 | copy.removeAndInsert(i, j); 40 | if (i < j) { 41 | for (int k = 0; k < i; k++) { 42 | assertEquals(p.get(k), copy.get(k)); 43 | } 44 | for (int k = i; k < j; k++) { 45 | assertEquals(p.get(k + 1), copy.get(k)); 46 | } 47 | assertEquals(p.get(i), copy.get(j)); 48 | for (int k = j + 1; k < p.length(); k++) { 49 | assertEquals(p.get(k), copy.get(k)); 50 | } 51 | assertNotEquals(p.hashCode(), copy.hashCode()); 52 | } else if (i > j) { 53 | for (int k = 0; k < j; k++) { 54 | assertEquals(p.get(k), copy.get(k)); 55 | } 56 | assertEquals(p.get(i), copy.get(j)); 57 | for (int k = j + 1; k <= i; k++) { 58 | assertEquals(p.get(k - 1), copy.get(k)); 59 | } 60 | for (int k = i + 1; k < p.length(); k++) { 61 | assertEquals(p.get(k), copy.get(k)); 62 | } 63 | assertNotEquals(p.hashCode(), copy.hashCode()); 64 | } else { 65 | assertEquals(p, copy); 66 | } 67 | } 68 | } 69 | } 70 | 71 | @Test 72 | public void testPermutationBlockRemoveInsert() { 73 | int[] a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 74 | int[] a1 = {7, 0, 1, 2, 3, 4, 5, 6, 8, 9, 10}; 75 | int[] a2 = {0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 2}; 76 | int[] a3 = {7, 8, 0, 1, 2, 3, 4, 5, 6, 9, 10}; 77 | int[] a4 = {0, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2}; 78 | int[] a5 = {0, 3, 4, 5, 6, 7, 1, 2, 8, 9, 10}; 79 | int[] a6 = {0, 7, 8, 1, 2, 3, 4, 5, 6, 9, 10}; 80 | Permutation p = new Permutation(a); 81 | Permutation p1 = new Permutation(a1); 82 | Permutation mutant = new Permutation(p); 83 | assertEquals(p.hashCode(), mutant.hashCode()); 84 | mutant.removeAndInsert(7, 1, 0); 85 | assertEquals(p1, mutant); 86 | assertNotEquals(p.hashCode(), mutant.hashCode()); 87 | Permutation p2 = new Permutation(a2); 88 | mutant = new Permutation(p); 89 | mutant.removeAndInsert(2, 1, 10); 90 | assertEquals(p2, mutant); 91 | Permutation p3 = new Permutation(a3); 92 | mutant = new Permutation(p); 93 | assertEquals(p.hashCode(), mutant.hashCode()); 94 | mutant.removeAndInsert(7, 2, 0); 95 | assertEquals(p3, mutant); 96 | assertNotEquals(p.hashCode(), mutant.hashCode()); 97 | Permutation p4 = new Permutation(a4); 98 | mutant = new Permutation(p); 99 | mutant.removeAndInsert(1, 2, 9); 100 | assertEquals(p4, mutant); 101 | Permutation p5 = new Permutation(a5); 102 | mutant = new Permutation(p); 103 | mutant.removeAndInsert(1, 2, 6); 104 | assertEquals(p5, mutant); 105 | Permutation p6 = new Permutation(a6); 106 | mutant = new Permutation(p); 107 | mutant.removeAndInsert(7, 2, 1); 108 | assertEquals(p6, mutant); 109 | 110 | mutant = new Permutation(p); 111 | mutant.removeAndInsert(1, 0, 3); 112 | assertEquals(p, mutant); 113 | mutant = new Permutation(p); 114 | mutant.removeAndInsert(1, 3, 1); 115 | assertEquals(p, mutant); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/PermutationReverseTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import java.util.SplittableRandom; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for reversing a Permutation. */ 30 | public class PermutationReverseTests { 31 | 32 | @Test 33 | public void testReverse0() { 34 | Permutation p1 = new Permutation(0); 35 | // verify reversing 0 length Permutation doesn't throw an exception. 36 | p1.reverse(); 37 | } 38 | 39 | @Test 40 | public void testReverseComplete() { 41 | for (int n = 1; n <= 8; n *= 2) { 42 | Permutation p = new Permutation(n, new SplittableRandom(42)); 43 | Permutation copy = new Permutation(p); 44 | assertEquals(p.hashCode(), copy.hashCode()); 45 | copy.reverse(); 46 | for (int i = 0; i < n; i++) { 47 | assertEquals(p.get(i), copy.get(n - 1 - i)); 48 | } 49 | if (n >= 2) { 50 | assertNotEquals(p.hashCode(), copy.hashCode()); 51 | } 52 | } 53 | } 54 | 55 | @Test 56 | public void testReverseSub() { 57 | Permutation p = new Permutation(8, new SplittableRandom(42)); 58 | for (int j = 0; j < p.length(); j++) { 59 | for (int k = j + 1; k < p.length(); k++) { 60 | Permutation copy = new Permutation(p); 61 | assertEquals(p.hashCode(), copy.hashCode()); 62 | copy.reverse(j, k); 63 | validateReversal(p, copy, j, k); 64 | assertNotEquals(p.hashCode(), copy.hashCode()); 65 | 66 | copy = new Permutation(p); 67 | assertEquals(p.hashCode(), copy.hashCode()); 68 | copy.reverse(k, j); 69 | validateReversal(p, copy, j, k); 70 | assertNotEquals(p.hashCode(), copy.hashCode()); 71 | } 72 | } 73 | } 74 | 75 | private void validateReversal(Permutation p, Permutation copy, int j, int k) { 76 | for (int i = 0; i < j; i++) { 77 | assertEquals(p.get(i), copy.get(i)); 78 | } 79 | int shift = 0; 80 | for (int i = j; i <= k; i++) { 81 | assertEquals(p.get(i), copy.get(k - shift)); 82 | shift++; 83 | } 84 | for (int i = k + 1; i < p.length(); i++) { 85 | assertEquals(p.get(i), copy.get(i)); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/PermutationRotateTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import java.util.SplittableRandom; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for rotating a Permutation. */ 30 | public class PermutationRotateTests { 31 | 32 | @Test 33 | public void testPermutationRotate() { 34 | Permutation p = new Permutation(10, new SplittableRandom(42)); 35 | for (int r = 0; r < p.length(); r++) { 36 | Permutation copy = new Permutation(p); 37 | assertEquals(p.hashCode(), copy.hashCode()); 38 | copy.rotate(r); 39 | for (int i = 0; i < p.length(); i++) { 40 | int j = (i + r) % p.length(); 41 | assertEquals(p.get(j), copy.get(i), "elements should be left rotated " + r + " places"); 42 | } 43 | if (r > 0) { 44 | assertNotEquals(p.hashCode(), copy.hashCode()); 45 | } 46 | } 47 | Permutation copy = new Permutation(p); 48 | assertEquals(p.hashCode(), copy.hashCode()); 49 | copy.rotate(p.length()); 50 | assertEquals(p, copy); 51 | assertEquals(p.hashCode(), copy.hashCode()); 52 | copy = new Permutation(p); 53 | assertEquals(p.hashCode(), copy.hashCode()); 54 | copy.rotate(-1); 55 | assertNotEquals(p.hashCode(), copy.hashCode()); 56 | for (int i = 1; i < p.length(); i++) { 57 | assertEquals(p.get(i - 1), copy.get(i), "elements should be RIGHT rotated 1 place"); 58 | } 59 | assertEquals(p.get(p.length() - 1), copy.get(0), "elements should be RIGHT rotated 1 place"); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/SharedTestHelpersPermutation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2005-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.permutations; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.junit.jupiter.api.*; 27 | 28 | /** Helpers shared by multiple test classes. */ 29 | public class SharedTestHelpersPermutation { 30 | 31 | final void validatePermutation(Permutation p, int n) { 32 | assertEquals(n, p.length()); 33 | boolean[] inP = new boolean[n]; 34 | for (int i = 0; i < p.length(); i++) { 35 | int el = p.get(i); 36 | assertTrue(el >= 0 && el < n); 37 | assertFalse(inP[el]); 38 | inP[el] = true; 39 | } 40 | } 41 | 42 | final double chiSquare(int[] buckets) { 43 | int x = 0; 44 | int n = 0; 45 | for (int e : buckets) { 46 | x = x + e * e; 47 | n += e; 48 | } 49 | return 1.0 * x / (n / buckets.length) - n; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/AcyclicEdgeDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for AcyclicEdgeDistance. */ 30 | public class AcyclicEdgeDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | AcyclicEdgeDistance d = new AcyclicEdgeDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 2 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | AcyclicEdgeDistance d = new AcyclicEdgeDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | AcyclicEdgeDistance d = new AcyclicEdgeDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testReversalIndependence() { 58 | AcyclicEdgeDistance d = new AcyclicEdgeDistance(); 59 | reversalInvariance(d); 60 | } 61 | 62 | @Test 63 | public void testAcyclicEdgeDistance() { 64 | AcyclicEdgeDistance d = new AcyclicEdgeDistance(); 65 | int[] a1 = {0, 1, 2, 3, 4, 5}; 66 | int[] a2 = {0, 2, 4, 1, 5, 3}; 67 | int[] a3 = {0, 1, 2, 4, 5, 3}; 68 | Permutation p1 = new Permutation(a1); 69 | Permutation p2 = new Permutation(a2); 70 | Permutation p3 = new Permutation(a3); 71 | assertEquals(5, d.distance(p1, p2)); 72 | p2.reverse(); 73 | assertEquals(5, d.distance(p1, p2)); 74 | assertEquals(2, d.distance(p1, p3)); 75 | p3.reverse(); 76 | assertEquals(2, d.distance(p1, p3)); 77 | } 78 | 79 | @Test 80 | public void testExceptions() { 81 | AcyclicEdgeDistance d = new AcyclicEdgeDistance(); 82 | IllegalArgumentException thrown = 83 | assertThrows( 84 | IllegalArgumentException.class, 85 | () -> d.distance(new Permutation(1), new Permutation(2))); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/CycleDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for CycleDistance. */ 30 | public class CycleDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | CycleDistance d = new CycleDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | CycleDistance d = new CycleDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | CycleDistance d = new CycleDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testCycleDistance() { 58 | CycleDistance d = new CycleDistance(); 59 | int[][] cases = { 60 | {1, 0}, 61 | {1, 2, 0}, 62 | {1, 2, 3, 0}, 63 | {1, 0, 3, 2}, 64 | {1, 2, 3, 4, 5, 6, 7, 0}, 65 | {7, 1, 2, 3, 4, 5, 6, 0}, 66 | {7, 1, 5, 3, 4, 2, 6, 0}, 67 | {7, 6, 5, 4, 3, 2, 1, 0}, 68 | {2, 3, 4, 5, 0, 1, 7, 6}, 69 | {15, 3, 4, 5, 6, 1, 7, 2, 9, 10, 11, 8, 13, 14, 12, 0} 70 | }; 71 | int[] expected = {1, 1, 1, 2, 1, 1, 2, 4, 3, 5}; 72 | for (int i = 0; i < expected.length; i++) { 73 | Permutation p1 = new Permutation(cases[i].length, 0); 74 | Permutation p2 = new Permutation(cases[i]); 75 | assertEquals(expected[i], d.distance(p1, p2)); 76 | assertEquals(expected[i], d.distance(p2, p1)); 77 | } 78 | IllegalArgumentException thrown = 79 | assertThrows( 80 | IllegalArgumentException.class, 81 | () -> d.distance(new Permutation(1), new Permutation(2))); 82 | } 83 | 84 | @Test 85 | public void testExceptions() { 86 | CycleDistance d = new CycleDistance(); 87 | IllegalArgumentException thrown = 88 | assertThrows( 89 | IllegalArgumentException.class, 90 | () -> d.distance(new Permutation(1), new Permutation(2))); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/CycleEditDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for CycleEditDistance. */ 30 | public class CycleEditDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | CycleEditDistance d = new CycleEditDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | CycleEditDistance d = new CycleEditDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | CycleEditDistance d = new CycleEditDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testCycleEditDistance() { 58 | CycleEditDistance d = new CycleEditDistance(); 59 | int[][] cases = { 60 | {1, 0}, 61 | {1, 2, 0}, 62 | {1, 2, 3, 0}, 63 | {1, 0, 3, 2}, 64 | {1, 2, 3, 4, 5, 6, 7, 0}, 65 | {7, 1, 2, 3, 4, 5, 6, 0}, 66 | {7, 1, 5, 3, 4, 2, 6, 0}, 67 | {7, 6, 5, 4, 3, 2, 1, 0}, 68 | {2, 3, 4, 5, 0, 1, 7, 6}, 69 | {15, 3, 4, 5, 6, 1, 7, 2, 9, 10, 11, 8, 13, 14, 12, 0}, 70 | {0, 1}, 71 | {0} 72 | }; 73 | int[] expected = {1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 0, 0}; 74 | for (int i = 0; i < expected.length; i++) { 75 | Permutation p1 = new Permutation(cases[i].length, 0); 76 | Permutation p2 = new Permutation(cases[i]); 77 | assertEquals(expected[i], d.distance(p1, p2)); 78 | assertEquals(expected[i], d.distance(p2, p1)); 79 | } 80 | } 81 | 82 | @Test 83 | public void testExceptions() { 84 | CycleEditDistance d = new CycleEditDistance(); 85 | IllegalArgumentException thrown = 86 | assertThrows( 87 | IllegalArgumentException.class, 88 | () -> d.distance(new Permutation(1), new Permutation(2))); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/CyclicEdgeDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.*; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for CyclicEdgeDistance. */ 30 | public class CyclicEdgeDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | CyclicEdgeDistance d = new CyclicEdgeDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 3 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | CyclicEdgeDistance d = new CyclicEdgeDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | CyclicEdgeDistance d = new CyclicEdgeDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testReversalIndependence() { 58 | CyclicEdgeDistance d = new CyclicEdgeDistance(); 59 | reversalInvariance(d); 60 | } 61 | 62 | @Test 63 | public void testRotationalInvariance() { 64 | CyclicEdgeDistance d = new CyclicEdgeDistance(); 65 | rotationalInvariance(d); 66 | } 67 | 68 | @Test 69 | public void testCyclicEdgeDistance() { 70 | CyclicEdgeDistance d = new CyclicEdgeDistance(); 71 | int[] a1 = {0, 1, 2, 3, 4, 5}; 72 | int[] a2 = {0, 2, 4, 1, 5, 3}; 73 | int[] a3 = {0, 1, 2, 4, 5, 3}; 74 | Permutation p1 = new Permutation(a1); 75 | Permutation p2 = new Permutation(a2); 76 | Permutation p3 = new Permutation(a3); 77 | assertEquals(6, d.distance(p1, p2)); 78 | p2.reverse(); 79 | assertEquals(6, d.distance(p1, p2)); 80 | p2.reverse(); 81 | for (int i = 1; i < a1.length; i++) { 82 | p2.rotate(1); 83 | assertEquals(6, d.distance(p1, p2)); 84 | } 85 | assertEquals(3, d.distance(p1, p3)); 86 | p3.reverse(); 87 | assertEquals(3, d.distance(p1, p3)); 88 | p3.reverse(); 89 | for (int i = 1; i < a1.length; i++) { 90 | p3.rotate(1); 91 | assertEquals(3, d.distance(p1, p3)); 92 | } 93 | } 94 | 95 | @Test 96 | public void testExceptions() { 97 | CyclicEdgeDistance d = new CyclicEdgeDistance(); 98 | IllegalArgumentException thrown = 99 | assertThrows( 100 | IllegalArgumentException.class, 101 | () -> d.distance(new Permutation(1), new Permutation(2))); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/CyclicIndependenceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for cyclic independence. */ 30 | public class CyclicIndependenceTests { 31 | 32 | @Test 33 | public void testCyclicIndependentDistance() { 34 | ExactMatchDistance em = new ExactMatchDistance(); 35 | CyclicIndependentDistance d = new CyclicIndependentDistance(em); 36 | int[] original = {0, 1, 2, 3}; 37 | int[] different = {0, 2, 1, 3}; 38 | Permutation p1 = new Permutation(original); 39 | Permutation p2 = new Permutation(original); 40 | Permutation pd = new Permutation(different); 41 | Permutation pr1 = new Permutation(p1); 42 | pr1.rotate(1); 43 | Permutation pr2 = new Permutation(p1); 44 | pr1.rotate(2); 45 | Permutation pr3 = new Permutation(p1); 46 | pr1.rotate(3); 47 | assertEquals(0, d.distance(p1, p2)); 48 | assertEquals(0, d.distance(p1, pr1)); 49 | assertEquals(0, d.distance(p1, pr2)); 50 | assertEquals(0, d.distance(p1, pr3)); 51 | assertEquals(2, d.distance(pd, p2)); 52 | assertEquals(2, d.distance(pd, pr1)); 53 | assertEquals(2, d.distance(pd, pr2)); 54 | assertEquals(2, d.distance(pd, pr3)); 55 | 56 | assertEquals(0, d.distancef(p1, p2)); 57 | assertEquals(0, d.distancef(p1, pr1)); 58 | assertEquals(0, d.distancef(p1, pr2)); 59 | assertEquals(0, d.distancef(p1, pr3)); 60 | assertEquals(2, d.distancef(pd, p2)); 61 | assertEquals(2, d.distancef(pd, pr1)); 62 | assertEquals(2, d.distancef(pd, pr2)); 63 | assertEquals(2, d.distancef(pd, pr3)); 64 | } 65 | 66 | @Test 67 | public void testCyclicIndependentDistanceDouble() { 68 | ExactMatchDistance em = new ExactMatchDistance(); 69 | CyclicIndependentDistanceDouble d = new CyclicIndependentDistanceDouble(em); 70 | int[] original = {0, 1, 2, 3}; 71 | int[] different = {0, 2, 1, 3}; 72 | Permutation p1 = new Permutation(original); 73 | Permutation p2 = new Permutation(original); 74 | Permutation pd = new Permutation(different); 75 | Permutation pr1 = new Permutation(p1); 76 | pr1.rotate(1); 77 | Permutation pr2 = new Permutation(p1); 78 | pr1.rotate(2); 79 | Permutation pr3 = new Permutation(p1); 80 | pr1.rotate(3); 81 | assertEquals(0, d.distancef(p1, p2)); 82 | assertEquals(0, d.distancef(p1, pr1)); 83 | assertEquals(0, d.distancef(p1, pr2)); 84 | assertEquals(0, d.distancef(p1, pr3)); 85 | assertEquals(2, d.distancef(pd, p2)); 86 | assertEquals(2, d.distancef(pd, pr1)); 87 | assertEquals(2, d.distancef(pd, pr2)); 88 | assertEquals(2, d.distancef(pd, pr3)); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/CyclicRTypeDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for CyclicRTypeDistance. */ 30 | public class CyclicRTypeDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | CyclicRTypeDistance d = new CyclicRTypeDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 2 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | CyclicRTypeDistance d = new CyclicRTypeDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | CyclicRTypeDistance d = new CyclicRTypeDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testRotationalInvariance() { 58 | CyclicRTypeDistance d = new CyclicRTypeDistance(); 59 | rotationalInvariance(d); 60 | } 61 | 62 | @Test 63 | public void testCyclicRTypeDistance() { 64 | CyclicRTypeDistance d = new CyclicRTypeDistance(); 65 | int[] a1 = {0, 1, 2, 3, 4, 5}; 66 | int[] a2 = {0, 2, 4, 1, 5, 3}; 67 | int[] a3 = {0, 1, 2, 4, 5, 3}; 68 | Permutation p1 = new Permutation(a1); 69 | Permutation p2 = new Permutation(a2); 70 | Permutation p3 = new Permutation(a3); 71 | assertEquals(6, d.distance(p1, p2)); 72 | for (int i = 1; i < a1.length; i++) { 73 | p2.rotate(1); 74 | assertEquals(6, d.distance(p1, p2)); 75 | } 76 | assertEquals(3, d.distance(p1, p3)); 77 | for (int i = 1; i < a1.length; i++) { 78 | p3.rotate(1); 79 | assertEquals(3, d.distance(p1, p3)); 80 | } 81 | Permutation r = new Permutation(p1); 82 | r.reverse(); 83 | assertEquals(6, d.distance(p1, r)); 84 | } 85 | 86 | @Test 87 | public void testExceptions() { 88 | CyclicRTypeDistance d = new CyclicRTypeDistance(); 89 | IllegalArgumentException thrown = 90 | assertThrows( 91 | IllegalArgumentException.class, 92 | () -> d.distance(new Permutation(1), new Permutation(2))); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/CyclicReversalIndependenceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for cyclic reversal independence. */ 30 | public class CyclicReversalIndependenceTests { 31 | 32 | @Test 33 | public void testCyclicReversalIndependentDistance() { 34 | ExactMatchDistance em = new ExactMatchDistance(); 35 | CyclicReversalIndependentDistance d = new CyclicReversalIndependentDistance(em); 36 | int[] original = {0, 1, 2, 3, 4}; 37 | int[] different = {3, 4, 0, 2, 1}; 38 | 39 | Permutation p = new Permutation(original); 40 | Permutation[] rotated = new Permutation[original.length]; 41 | Permutation[] reversed = new Permutation[original.length]; 42 | rotated[0] = new Permutation(original); 43 | for (int i = 1; i < rotated.length; i++) { 44 | rotated[i] = new Permutation(original); 45 | rotated[i].rotate(i); 46 | } 47 | for (int i = 0; i < reversed.length; i++) { 48 | reversed[i] = new Permutation(rotated[i]); 49 | reversed[i].reverse(); 50 | } 51 | for (int i = 0; i < rotated.length; i++) { 52 | assertEquals(0, d.distance(p, rotated[i])); 53 | assertEquals(0, d.distance(p, reversed[i])); 54 | assertEquals(0, d.distancef(p, rotated[i])); 55 | assertEquals(0, d.distancef(p, reversed[i])); 56 | } 57 | rotated[0] = new Permutation(different); 58 | for (int i = 1; i < rotated.length; i++) { 59 | rotated[i] = new Permutation(different); 60 | rotated[i].rotate(i); 61 | } 62 | for (int i = 0; i < reversed.length; i++) { 63 | reversed[i] = new Permutation(rotated[i]); 64 | reversed[i].reverse(); 65 | } 66 | for (int i = 0; i < rotated.length; i++) { 67 | assertEquals(2, d.distance(p, rotated[i])); 68 | assertEquals(2, d.distance(p, reversed[i])); 69 | assertEquals(2, d.distancef(p, rotated[i])); 70 | assertEquals(2, d.distancef(p, reversed[i])); 71 | } 72 | } 73 | 74 | @Test 75 | public void testCyclicReversalIndependentDistanceDouble() { 76 | ExactMatchDistance em = new ExactMatchDistance(); 77 | CyclicReversalIndependentDistanceDouble d = new CyclicReversalIndependentDistanceDouble(em); 78 | int[] original = {0, 1, 2, 3, 4}; 79 | int[] different = {3, 4, 0, 2, 1}; 80 | 81 | Permutation p = new Permutation(original); 82 | Permutation[] rotated = new Permutation[original.length]; 83 | Permutation[] reversed = new Permutation[original.length]; 84 | rotated[0] = new Permutation(original); 85 | for (int i = 1; i < rotated.length; i++) { 86 | rotated[i] = new Permutation(original); 87 | rotated[i].rotate(i); 88 | } 89 | for (int i = 0; i < reversed.length; i++) { 90 | reversed[i] = new Permutation(rotated[i]); 91 | reversed[i].reverse(); 92 | } 93 | for (int i = 0; i < rotated.length; i++) { 94 | assertEquals(0, d.distancef(p, rotated[i])); 95 | assertEquals(0, d.distancef(p, reversed[i])); 96 | } 97 | rotated[0] = new Permutation(different); 98 | for (int i = 1; i < rotated.length; i++) { 99 | rotated[i] = new Permutation(different); 100 | rotated[i].rotate(i); 101 | } 102 | for (int i = 0; i < reversed.length; i++) { 103 | reversed[i] = new Permutation(rotated[i]); 104 | reversed[i].reverse(); 105 | } 106 | for (int i = 0; i < rotated.length; i++) { 107 | assertEquals(2, d.distancef(p, rotated[i])); 108 | assertEquals(2, d.distancef(p, reversed[i])); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/DeviationDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for DeviationDistance. */ 30 | public class DeviationDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | DeviationDistance d = new DeviationDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | DeviationDistance d = new DeviationDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | DeviationDistance d = new DeviationDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testExceptions() { 58 | DeviationDistance d = new DeviationDistance(); 59 | IllegalArgumentException thrown = 60 | assertThrows( 61 | IllegalArgumentException.class, 62 | () -> d.distance(new Permutation(1), new Permutation(2))); 63 | } 64 | 65 | @Test 66 | public void testDeviationDistance() { 67 | DeviationDistance d = new DeviationDistance(); 68 | for (int n = 2; n <= 10; n++) { 69 | Permutation p = new Permutation(n); 70 | Permutation copy = new Permutation(p); 71 | for (int i = 1; i < n; i++) { 72 | // rotations are a special case that are easy to compute analytically (perfect for unit 73 | // tests) 74 | copy.rotate(1); 75 | int expected = 2 * i * (n - i); 76 | assertEquals(expected, d.distance(p, copy)); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/ExactMatchDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for ExactMatchDistance. */ 30 | public class ExactMatchDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | ExactMatchDistance d = new ExactMatchDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | ExactMatchDistance d = new ExactMatchDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | ExactMatchDistance d = new ExactMatchDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testExactMatchDistance() { 58 | ExactMatchDistance d = new ExactMatchDistance(); 59 | int[] a1 = {0, 1, 2, 3, 4, 5}; 60 | int[] a2 = {5, 0, 1, 2, 3, 4}; 61 | int[] a3 = {5, 1, 2, 3, 4, 0}; 62 | int[] a4 = {0, 3, 2, 1, 4, 5}; 63 | Permutation p1 = new Permutation(a1); 64 | Permutation p2 = new Permutation(a2); 65 | Permutation p3 = new Permutation(a3); 66 | Permutation p4 = new Permutation(a4); 67 | assertEquals(6, d.distance(p1, p2)); 68 | assertEquals(2, d.distance(p1, p3)); 69 | assertEquals(2, d.distance(p1, p4)); 70 | } 71 | 72 | @Test 73 | public void testExceptions() { 74 | ExactMatchDistance d = new ExactMatchDistance(); 75 | IllegalArgumentException thrown = 76 | assertThrows( 77 | IllegalArgumentException.class, 78 | () -> d.distance(new Permutation(1), new Permutation(2))); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/InterchangeDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for InterchangeDistance. */ 30 | public class InterchangeDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | InterchangeDistance d = new InterchangeDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | InterchangeDistance d = new InterchangeDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | InterchangeDistance d = new InterchangeDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testInterchangeDistance() { 58 | InterchangeDistance d = new InterchangeDistance(); 59 | int[] a1 = {0, 1, 2, 3, 4, 5}; 60 | int[] a2 = {2, 4, 1, 0, 5, 3}; 61 | int[] a3 = {5, 1, 2, 3, 4, 0}; 62 | int[] a4 = {0, 3, 2, 1, 4, 5}; 63 | int[] a5 = {2, 5, 4, 1, 0, 3}; 64 | Permutation p1 = new Permutation(a1); 65 | Permutation p2 = new Permutation(a2); 66 | Permutation p3 = new Permutation(a3); 67 | Permutation p4 = new Permutation(a4); 68 | Permutation p5 = new Permutation(a5); 69 | 70 | assertEquals(5, d.distance(p1, p2)); 71 | assertEquals(1, d.distance(p1, p3)); 72 | assertEquals(1, d.distance(p1, p4)); 73 | assertEquals(4, d.distance(p1, p5)); 74 | } 75 | 76 | @Test 77 | public void testExceptions() { 78 | InterchangeDistance d = new InterchangeDistance(); 79 | IllegalArgumentException thrown = 80 | assertThrows( 81 | IllegalArgumentException.class, 82 | () -> d.distance(new Permutation(1), new Permutation(2))); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/KCycleDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for KCycleDistance. */ 30 | public class KCycleDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | for (int k = 2; k <= 5; k++) { 35 | KCycleDistance d = new KCycleDistance(k); 36 | for (int n = 0; n <= 7; n++) { 37 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "n,k=" + n + "," + k); 38 | } 39 | } 40 | } 41 | 42 | @Test 43 | public void testMax() { 44 | for (int k = 2; k <= 5; k++) { 45 | KCycleDistance d = new KCycleDistance(k); 46 | for (int n = 0; n <= 7; n++) { 47 | int expected = bruteForceComputeMax(d, n); 48 | assertEquals(expected, d.max(n), "n,k=" + n + "," + k); 49 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 50 | } 51 | } 52 | } 53 | 54 | @Test 55 | public void testAllOneCycle() { 56 | for (int k = 2; k <= 5; k++) { 57 | KCycleDistance d = new KCycleDistance(k); 58 | // All one cycle 59 | for (int n = 2; n <= 16; n *= 2) { 60 | int[] perm = new int[n]; 61 | for (int i = 0; i < n; i++) { 62 | perm[i] = (i + 1) % n; 63 | } 64 | Permutation p1 = new Permutation(n, 0); 65 | Permutation p2 = new Permutation(perm); 66 | int expected = 1 + (n > k ? (int) Math.ceil((n - k) / (k - 1.0)) : 0); 67 | assertEquals(expected, d.distance(p1, p2)); 68 | assertEquals(expected, d.distance(p2, p1)); 69 | } 70 | } 71 | } 72 | 73 | @Test 74 | public void testMaximalCycles() { 75 | for (int k = 2; k <= 5; k++) { 76 | KCycleDistance d = new KCycleDistance(k); 77 | // maximal cycles 78 | for (int n = 2; n <= 16; n *= 2) { 79 | int[] perm = new int[n]; 80 | for (int i = 0; i < n; i++) { 81 | if (i % 2 == 1) { 82 | perm[i] = perm[i - 1]; 83 | perm[i - 1] = i; 84 | } else { 85 | perm[i] = i; 86 | } 87 | } 88 | Permutation p1 = new Permutation(n, 0); 89 | Permutation p2 = new Permutation(perm); 90 | int expected = n / 2; 91 | assertEquals(expected, d.distance(p1, p2)); 92 | assertEquals(expected, d.distance(p2, p1)); 93 | } 94 | } 95 | } 96 | 97 | @Test 98 | public void testMixOfCycleLengths() { 99 | int[] p = {1, 0, 4, 2, 3, 6, 7, 8, 5, 10, 11, 12, 13, 9, 19, 14, 15, 16, 17, 18}; 100 | int[] expectedDist = {0, 0, 15, 9, 7, 6}; 101 | for (int k = 2; k <= 5; k++) { 102 | KCycleDistance d = new KCycleDistance(k); 103 | // Mix of cycle lengths 104 | Permutation p1 = new Permutation(p.length, 0); 105 | Permutation p2 = new Permutation(p); 106 | assertEquals(expectedDist[k], d.distance(p1, p2)); 107 | assertEquals(expectedDist[k], d.distance(p2, p1)); 108 | IllegalArgumentException thrown = 109 | assertThrows( 110 | IllegalArgumentException.class, 111 | () -> d.distance(new Permutation(1), new Permutation(2))); 112 | } 113 | } 114 | 115 | @Test 116 | public void testExceptions() { 117 | IllegalArgumentException thrown = 118 | assertThrows(IllegalArgumentException.class, () -> new KCycleDistance(1)); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/KendallTauDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for KendallTauDistance. */ 30 | public class KendallTauDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | KendallTauDistance d = new KendallTauDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | KendallTauDistance d = new KendallTauDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | KendallTauDistance d = new KendallTauDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testKendallTauDistance() { 58 | KendallTauDistance d = new KendallTauDistance(); 59 | for (int n = 2; n <= 10; n++) { 60 | // maximal distance is permutation reversed 61 | Permutation p = new Permutation(n); 62 | Permutation copy = new Permutation(p); 63 | copy.reverse(); 64 | int expected = n * (n - 1) / 2; 65 | assertEquals(expected, d.distance(p, copy)); 66 | copy.reverse(); 67 | copy.swap(0, n - 1); 68 | expected = 2 * n - 3; 69 | assertEquals(expected, d.distance(p, copy)); 70 | } 71 | Permutation p = new Permutation(6); 72 | for (Permutation q : p) { 73 | assertEquals(naiveKendalTau(p, q), d.distance(p, q)); 74 | } 75 | } 76 | 77 | @Test 78 | public void testExceptions() { 79 | KendallTauDistance d = new KendallTauDistance(); 80 | IllegalArgumentException thrown = 81 | assertThrows( 82 | IllegalArgumentException.class, 83 | () -> d.distance(new Permutation(1), new Permutation(2))); 84 | } 85 | 86 | private int naiveKendalTau(Permutation p1, Permutation p2) { 87 | int count = 0; 88 | int L1 = p1.length(); 89 | 90 | int[] invP1 = p1.getInverse(); 91 | int[] invP2 = p2.getInverse(); 92 | 93 | for (int i = 0; i < L1 - 1; i++) { 94 | for (int j = i + 1; j < L1; j++) { 95 | if ((invP1[i] - invP1[j]) * (invP2[i] - invP2[j]) < 0) count++; 96 | } 97 | } 98 | 99 | return count; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/LeeDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for LeeDistance. */ 30 | public class LeeDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | LeeDistance d = new LeeDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | LeeDistance d = new LeeDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | LeeDistance d = new LeeDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testExceptions() { 58 | LeeDistance d = new LeeDistance(); 59 | IllegalArgumentException thrown = 60 | assertThrows( 61 | IllegalArgumentException.class, 62 | () -> d.distance(new Permutation(1), new Permutation(2))); 63 | } 64 | 65 | @Test 66 | public void testLeeDistance() { 67 | LeeDistance d = new LeeDistance(); 68 | for (int n = 2; n <= 10; n++) { 69 | Permutation p = new Permutation(n); 70 | Permutation copy = new Permutation(p); 71 | for (int i = 1; i < n; i++) { 72 | // rotations are a special case that are easy to compute analytically (perfect for unit 73 | // tests) 74 | copy.rotate(1); 75 | int expected = Math.min(i, n - i) * n; 76 | assertEquals(expected, d.distance(p, copy)); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/RTypeDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for RTypeDistance. */ 30 | public class RTypeDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | RTypeDistance d = new RTypeDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | RTypeDistance d = new RTypeDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | RTypeDistance d = new RTypeDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testRTypeDistance() { 58 | RTypeDistance d = new RTypeDistance(); 59 | int[] a1 = {0, 1, 2, 3, 4, 5}; 60 | int[] a2 = {0, 2, 4, 1, 5, 3}; 61 | int[] a3 = {0, 1, 2, 4, 5, 3}; 62 | Permutation p1 = new Permutation(a1); 63 | Permutation p2 = new Permutation(a2); 64 | Permutation p3 = new Permutation(a3); 65 | assertEquals(5, d.distance(p1, p2)); 66 | assertEquals(2, d.distance(p1, p3)); 67 | Permutation r = new Permutation(p1); 68 | r.reverse(); 69 | assertEquals(5, d.distance(p1, r)); 70 | } 71 | 72 | @Test 73 | public void testExceptions() { 74 | RTypeDistance d = new RTypeDistance(); 75 | IllegalArgumentException thrown = 76 | assertThrows( 77 | IllegalArgumentException.class, 78 | () -> d.distance(new Permutation(1), new Permutation(2))); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/ReinsertionDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for ReinsertionDistance. */ 30 | public class ReinsertionDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | ReinsertionDistance d = new ReinsertionDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | ReinsertionDistance d = new ReinsertionDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | ReinsertionDistance d = new ReinsertionDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testSameAsEditDistanceDefaults() { 58 | ReinsertionDistance d = new ReinsertionDistance(); 59 | Permutation p = new Permutation(5); 60 | EditDistance edit = new EditDistance(); 61 | for (Permutation q : p) { 62 | // NOTE: If this assertion fails, problem is either in ReinsertionDistance or EditDistance 63 | // Should correspond if they are both correct. 64 | assertEquals(edit.distancef(p, q), d.distancef(p, q)); 65 | assertEquals(edit.distancef(q, p), d.distancef(q, p)); 66 | } 67 | } 68 | 69 | @Test 70 | public void testReinsertionDistance() { 71 | ReinsertionDistance d = new ReinsertionDistance(); 72 | for (int n = 2; n <= 10; n++) { 73 | // maximal distance is permutation reversed 74 | Permutation p = new Permutation(n); 75 | Permutation copy = new Permutation(p); 76 | copy.reverse(); 77 | int expected = n - 1; 78 | assertEquals(expected, d.distance(p, copy)); 79 | assertEquals(expected, d.distance(copy, p)); 80 | } 81 | int[] a1 = {0, 1, 2, 3, 4, 5}; 82 | int[] a2 = {0, 4, 2, 3, 1, 5}; 83 | int[] a3 = {1, 5, 4, 2, 3, 0}; 84 | int[] a4 = {5, 3, 1, 2, 0, 4}; 85 | Permutation p1 = new Permutation(a1); 86 | Permutation p2 = new Permutation(a2); 87 | Permutation p3 = new Permutation(a3); 88 | Permutation p4 = new Permutation(a4); 89 | assertEquals(2, d.distance(p1, p2)); 90 | assertEquals(3, d.distance(p1, p3)); 91 | assertEquals(3, d.distance(p1, p4)); 92 | } 93 | 94 | @Test 95 | public void testExceptions() { 96 | ReinsertionDistance d = new ReinsertionDistance(); 97 | IllegalArgumentException thrown = 98 | assertThrows( 99 | IllegalArgumentException.class, 100 | () -> d.distance(new Permutation(1), new Permutation(2))); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/ReversalDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for ReversalDistance. */ 30 | public class ReversalDistanceTests { 31 | 32 | @Test 33 | public void testMax() { 34 | ReversalDistance d = new ReversalDistance(0); 35 | assertEquals(0, d.max(0)); 36 | d = new ReversalDistance(1); 37 | assertEquals(0, d.max(1)); 38 | d = new ReversalDistance(2); 39 | assertEquals(1, d.max(2)); 40 | d = new ReversalDistance(3); 41 | assertEquals(2, d.max(3)); 42 | d = new ReversalDistance(4); 43 | assertEquals(3, d.max(4)); 44 | } 45 | 46 | @Test 47 | public void testReversalDistance() { 48 | ReversalDistance d4 = new ReversalDistance(4); 49 | int[] a4 = {0, 1, 2, 3}; 50 | int[] a4_2 = {1, 0, 3, 2}; 51 | Permutation p4 = new Permutation(a4); 52 | Permutation p4_2 = new Permutation(a4_2); 53 | assertEquals(2, d4.distance(p4, p4_2)); 54 | ReversalDistance d5 = new ReversalDistance(5); 55 | int[] a5 = {0, 1, 4, 2, 3}; 56 | int[] a5_2 = {1, 0, 4, 3, 2}; 57 | Permutation p5 = new Permutation(a5); 58 | Permutation p5_2 = new Permutation(a5_2); 59 | assertEquals(2, d5.distance(p5, p5_2)); 60 | 61 | ReversalDistance d = new ReversalDistance(); 62 | assertEquals(2, d.distance(p5, p5_2)); 63 | assertEquals(4, d.max(5)); 64 | 65 | IllegalArgumentException thrown = 66 | assertThrows( 67 | IllegalArgumentException.class, 68 | () -> d5.distance(new Permutation(5), new Permutation(6))); 69 | thrown = 70 | assertThrows( 71 | IllegalArgumentException.class, 72 | () -> d5.distance(new Permutation(6), new Permutation(6))); 73 | thrown = assertThrows(IllegalArgumentException.class, () -> new ReversalDistance(-1)); 74 | thrown = assertThrows(IllegalArgumentException.class, () -> new ReversalDistance(13)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/ReversalIndependenceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for reversal independence. */ 30 | public class ReversalIndependenceTests { 31 | 32 | @Test 33 | public void testReversalIndependentDistance() { 34 | ExactMatchDistance em = new ExactMatchDistance(); 35 | ReversalIndependentDistance d = new ReversalIndependentDistance(em); 36 | int[] original = {0, 1, 2, 3, 4, 5, 6}; 37 | int[] other = {0, 5, 4, 3, 2, 1, 6}; 38 | int[] other2 = {6, 1, 2, 3, 4, 5, 0}; 39 | int[] reversed = {6, 5, 4, 3, 2, 1, 0}; 40 | Permutation p1 = new Permutation(original); 41 | Permutation p2 = new Permutation(original); 42 | Permutation pr = new Permutation(reversed); 43 | Permutation p4to2 = new Permutation(other); 44 | Permutation p2to4 = new Permutation(other2); 45 | assertEquals(0, d.distance(p1, p2)); 46 | assertEquals(0, d.distance(p1, pr)); 47 | assertEquals(0, d.distance(pr, p2)); 48 | assertEquals(2, d.distance(p1, p4to2)); 49 | assertEquals(2, d.distance(p4to2, p1)); 50 | assertEquals(2, d.distance(p1, p2to4)); 51 | assertEquals(2, d.distance(p2to4, p1)); 52 | assertEquals(0, d.distancef(p1, p2)); 53 | assertEquals(0, d.distancef(p1, pr)); 54 | assertEquals(0, d.distancef(pr, p2)); 55 | assertEquals(2, d.distancef(p1, p4to2)); 56 | assertEquals(2, d.distancef(p4to2, p1)); 57 | assertEquals(2, d.distancef(p1, p2to4)); 58 | assertEquals(2, d.distancef(p2to4, p1)); 59 | } 60 | 61 | @Test 62 | public void testReversalIndependentDistanceDouble() { 63 | ExactMatchDistance em = new ExactMatchDistance(); 64 | ReversalIndependentDistanceDouble d = new ReversalIndependentDistanceDouble(em); 65 | int[] original = {0, 1, 2, 3, 4, 5, 6}; 66 | int[] other = {0, 5, 4, 3, 2, 1, 6}; 67 | int[] other2 = {6, 1, 2, 3, 4, 5, 0}; 68 | int[] reversed = {6, 5, 4, 3, 2, 1, 0}; 69 | Permutation p1 = new Permutation(original); 70 | Permutation p2 = new Permutation(original); 71 | Permutation pr = new Permutation(reversed); 72 | Permutation p4to2 = new Permutation(other); 73 | Permutation p2to4 = new Permutation(other2); 74 | assertEquals(0, d.distancef(p1, p2)); 75 | assertEquals(0, d.distancef(p1, pr)); 76 | assertEquals(0, d.distancef(pr, p2)); 77 | assertEquals(2, d.distancef(p1, p4to2)); 78 | assertEquals(2, d.distancef(p4to2, p1)); 79 | assertEquals(2, d.distancef(p1, p2to4)); 80 | assertEquals(2, d.distancef(p2to4, p1)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/ScrambleDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for ScrambleDistance. */ 30 | public class ScrambleDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testMax() { 34 | ScrambleDistance d = new ScrambleDistance(); 35 | assertEquals(0, d.max(0)); 36 | assertEquals(0, d.max(1)); 37 | for (int n = 2; n <= 10; n++) { 38 | assertEquals(1, d.max(n)); 39 | } 40 | } 41 | 42 | @Test 43 | public void testIdenticalPermutations() { 44 | ScrambleDistance d = new ScrambleDistance(); 45 | identicalPermutations(d); 46 | } 47 | 48 | @Test 49 | public void testScrambleDistance() { 50 | ScrambleDistance d = new ScrambleDistance(); 51 | for (int i = 2; i <= 10; i++) { 52 | Permutation p1 = new Permutation(i); 53 | Permutation p2 = new Permutation(p1); 54 | p2.scramble(true); 55 | assertEquals(1, d.distance(p1, p2)); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/SharedTestForPermutationDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** Shared by several test classes. */ 30 | public class SharedTestForPermutationDistance { 31 | 32 | final void identicalPermutations(PermutationDistanceMeasurer d) { 33 | for (int n = 0; n <= 10; n++) { 34 | Permutation p = new Permutation(n); 35 | Permutation copy = new Permutation(p); 36 | assertEquals( 37 | 0, 38 | d.distance(p, copy), 39 | "distance of a permutation to itself should be 0; length was " + n); 40 | assertEquals( 41 | 0, d.distance(p, p), "distance of a permutation to itself should be 0; length was " + n); 42 | } 43 | } 44 | 45 | final void reversalInvariance(PermutationDistanceMeasurer d) { 46 | for (int n = 0; n <= 10; n++) { 47 | Permutation p = new Permutation(n); 48 | Permutation copy = new Permutation(p); 49 | copy.reverse(); 50 | assertEquals(0, d.distance(p, copy)); 51 | } 52 | } 53 | 54 | final void rotationalInvariance(PermutationDistanceMeasurer d) { 55 | for (int n = 2; n <= 10; n++) { 56 | Permutation p = new Permutation(n); 57 | Permutation copy = new Permutation(p); 58 | for (int i = 1; i < n; i++) { 59 | copy.rotate(1); 60 | assertEquals(0, d.distance(p, copy)); 61 | } 62 | } 63 | } 64 | 65 | final int bruteForceComputeMax(PermutationDistanceMeasurer d, int n) { 66 | int max = 0; 67 | Permutation p1 = new Permutation(n, 0); 68 | for (Permutation p2 : p1) { 69 | max = Math.max(max, d.distance(p1, p2)); 70 | } 71 | return max; 72 | } 73 | 74 | final double validateNormalizedDistance(NormalizedPermutationDistanceMeasurer d, int n) { 75 | double max = 0; 76 | Permutation p1 = new Permutation(n, 0); 77 | for (Permutation p2 : p1) { 78 | max = Math.max(max, d.normalizedDistance(p1, p2)); 79 | } 80 | return max; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/SharedTestForPermutationDistanceDouble.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** Shared by several test classes. */ 30 | public class SharedTestForPermutationDistanceDouble { 31 | 32 | final void identicalPermutationsDouble(PermutationDistanceMeasurerDouble d) { 33 | for (int n = 0; n <= 10; n++) { 34 | Permutation p = new Permutation(n); 35 | Permutation copy = new Permutation(p); 36 | assertEquals( 37 | 0.0, 38 | d.distancef(p, copy), 39 | "distance of a permutation to itself should be 0; length was " + n); 40 | assertEquals( 41 | 0.0, 42 | d.distancef(p, p), 43 | "distance of a permutation to itself should be 0; length was " + n); 44 | } 45 | } 46 | 47 | final double bruteForceComputeMaxD(PermutationDistanceMeasurerDouble d, int n) { 48 | double max = 0; 49 | Permutation p1 = new Permutation(n, 0); 50 | for (Permutation p2 : p1) { 51 | max = Math.max(max, d.distancef(p1, p2)); 52 | } 53 | return max; 54 | } 55 | 56 | final double validateNormalizedDistanceD(NormalizedPermutationDistanceMeasurerDouble d, int n) { 57 | double max = 0; 58 | Permutation p1 = new Permutation(n, 0); 59 | for (Permutation p2 : p1) { 60 | max = Math.max(max, d.normalizedDistance(p1, p2)); 61 | } 62 | return max; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/permutations/distance/SquaredDeviationDistanceTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | * 21 | */ 22 | package org.cicirello.permutations.distance; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.permutations.Permutation; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit tests for SquaredDeviationDistance. */ 30 | public class SquaredDeviationDistanceTests extends SharedTestForPermutationDistance { 31 | 32 | @Test 33 | public void testNormalized() { 34 | SquaredDeviationDistance d = new SquaredDeviationDistance(); 35 | for (int n = 0; n <= 7; n++) { 36 | assertEquals(n <= 1 ? 0.0 : 1.0, validateNormalizedDistance(d, n), "Failed on length: " + n); 37 | } 38 | } 39 | 40 | @Test 41 | public void testMax() { 42 | SquaredDeviationDistance d = new SquaredDeviationDistance(); 43 | for (int n = 0; n <= 7; n++) { 44 | int expected = bruteForceComputeMax(d, n); 45 | assertEquals(expected, d.max(n), "Failed on length: " + n); 46 | assertEquals(1.0 * expected, d.maxf(n), "Failed on length: " + n); 47 | } 48 | } 49 | 50 | @Test 51 | public void testIdenticalPermutations() { 52 | SquaredDeviationDistance d = new SquaredDeviationDistance(); 53 | identicalPermutations(d); 54 | } 55 | 56 | @Test 57 | public void testExceptions() { 58 | SquaredDeviationDistance d = new SquaredDeviationDistance(); 59 | IllegalArgumentException thrown = 60 | assertThrows( 61 | IllegalArgumentException.class, 62 | () -> d.distance(new Permutation(1), new Permutation(2))); 63 | } 64 | 65 | @Test 66 | public void testSquaredDeviationDistance() { 67 | SquaredDeviationDistance d = new SquaredDeviationDistance(); 68 | for (int n = 2; n <= 10; n++) { 69 | Permutation p = new Permutation(n); 70 | Permutation copy = new Permutation(p); 71 | for (int i = 1; i < n; i++) { 72 | // rotations are a special case that are easy to compute analytically (perfect for unit 73 | // tests) 74 | copy.rotate(1); 75 | int expected = i * i * (n - i) + i * (n - i) * (n - i); 76 | assertEquals(expected, d.distance(p, copy)); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/sequences/SequenceSamplerStatisticalTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * JavaPermutationTools: A Java library for computation on permutations and sequences 3 | * Copyright 2019-2023 Vincent A. Cicirello, . 4 | * 5 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 6 | * 7 | * JavaPermutationTools is free software: you can 8 | * redistribute it and/or modify it under the terms of the GNU 9 | * General Public License as published by the Free Software 10 | * Foundation, either version 3 of the License, or (at your 11 | * option) any later version. 12 | * 13 | * JavaPermutationTools is distributed in the hope 14 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 15 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | * PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with JavaPermutationTools. If not, see . 21 | */ 22 | package org.cicirello.sequences; 23 | 24 | import static org.junit.jupiter.api.Assertions.*; 25 | 26 | import org.cicirello.math.stats.Statistics; 27 | import org.junit.jupiter.api.*; 28 | 29 | /** JUnit statistical tests for the SequenceSampler class. */ 30 | public class SequenceSamplerStatisticalTests { 31 | 32 | // Set this is true to run the t-test. Due to randomness, 33 | // the t statistics won't be exactly the same each time. 34 | // An occasional failure is expected if this test is run a large enough times. 35 | // E.g., Test case is implemented with an alpha = 0.01, so 1 in 100 failures 36 | // is OK. And it runs several tests for different length arrays, etc. 37 | // So set this to true only if you change the code, and then set back to false 38 | // after passing. 39 | private static final boolean DISABLE_T_TEST = true; 40 | 41 | private static final int TTEST_NUM_SAMPLES = 100000; // 101; 42 | 43 | // Two-sided test, so alpha=0.01 level needs tCrit_{1 - alpha/2} = tCrit_{0.995} 44 | // This first one is 100 degrees of freedom (use for TTEST_NUM_SAMPLES = 101). 45 | // The second one is for infinite number of samples (use for very large TTEST_NUM_SAMPLES). 46 | private static final double CRITICAL_VALUE_995 = 2.626; 47 | private static final double CRITICAL_VALUE_995_INF = 2.576; 48 | 49 | @Test 50 | public void testSamplePTTest() { 51 | if (DISABLE_T_TEST) { 52 | return; 53 | } 54 | final double sqrt = Math.sqrt(TTEST_NUM_SAMPLES); 55 | for (int n = 1; n <= 10; n++) { 56 | int[] array = new int[n]; 57 | for (double p = 0.25; p <= 0.8; p += 0.25) { 58 | int[] L = new int[TTEST_NUM_SAMPLES]; 59 | for (int i = 0; i < TTEST_NUM_SAMPLES; i++) { 60 | L[i] = SequenceSampler.sample(array, p).length; 61 | } 62 | double stDev = Math.sqrt(Statistics.varianceSample(L)); 63 | double t = Math.abs(sqrt * (Statistics.mean(L) - n * p) / stDev); 64 | double crit = TTEST_NUM_SAMPLES == 101 ? CRITICAL_VALUE_995 : CRITICAL_VALUE_995_INF; 65 | System.out.println("t=" + t); 66 | assertTrue(t < crit, "t test for sample size, t=" + t); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/org/cicirello/sequences/distance/InternalTestHelpersSequenceDistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-2022 Vincent A. Cicirello, . 3 | * 4 | * This file is part of JavaPermutationTools (https://jpt.cicirello.org/). 5 | * 6 | * JavaPermutationTools is free software: you can 7 | * redistribute it and/or modify it under the terms of the GNU 8 | * General Public License as published by the Free Software 9 | * Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * JavaPermutationTools is distributed in the hope 13 | * that it will be useful, but WITHOUT ANY WARRANTY; without even 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU General Public License for more 16 | * details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with JavaPermutationTools. If not, see . 20 | */ 21 | package org.cicirello.sequences.distance; 22 | 23 | import static org.junit.jupiter.api.Assertions.*; 24 | 25 | import java.util.ArrayList; 26 | import java.util.concurrent.ThreadLocalRandom; 27 | import org.junit.jupiter.api.*; 28 | 29 | public class InternalTestHelpersSequenceDistance { 30 | 31 | final void identicalSequences(SequenceDistanceMeasurer d) { 32 | for (int n = 0; n <= 10; n++) { 33 | int[] a1 = new int[n]; 34 | long[] a2 = new long[n]; 35 | short[] a3 = new short[n]; 36 | byte[] a4 = new byte[n]; 37 | char[] a5 = new char[n]; 38 | float[] a6 = new float[n]; 39 | double[] a7 = new double[n]; 40 | boolean[] a8 = new boolean[n]; 41 | for (int i = 0; i < n; i++) { 42 | a1[i] = ThreadLocalRandom.current().nextInt(100); 43 | a2[i] = ThreadLocalRandom.current().nextInt(100); 44 | a3[i] = (short) ThreadLocalRandom.current().nextInt(100); 45 | a4[i] = (byte) ThreadLocalRandom.current().nextInt(100); 46 | a5[i] = (char) ThreadLocalRandom.current().nextInt(100); 47 | a6[i] = ThreadLocalRandom.current().nextInt(100); 48 | a7[i] = ThreadLocalRandom.current().nextInt(100); 49 | a8[i] = ThreadLocalRandom.current().nextBoolean(); 50 | } 51 | String a9 = new String(a5); 52 | // distance of a sequence to itself should be 0 53 | assertEquals(0, d.distance(a1, a1.clone())); 54 | assertEquals(0, d.distance(a2, a2.clone())); 55 | assertEquals(0, d.distance(a3, a3.clone())); 56 | assertEquals(0, d.distance(a4, a4.clone())); 57 | assertEquals(0, d.distance(a5, a5.clone())); 58 | assertEquals(0, d.distance(a6, a6.clone())); 59 | assertEquals(0, d.distance(a7, a7.clone())); 60 | assertEquals(0, d.distance(a8, a8.clone())); 61 | assertEquals(0, d.distance(a9, new String(a9))); 62 | } 63 | } 64 | 65 | final ArrayList toList(String[] a) { 66 | ArrayList list = new ArrayList(); 67 | for (String s : a) list.add(s); 68 | return list; 69 | } 70 | 71 | final ArrayList toList(NonComparable[] a) { 72 | ArrayList list = new ArrayList(); 73 | for (NonComparable s : a) list.add(s); 74 | return list; 75 | } 76 | 77 | static final class NonComparable { 78 | private int id; 79 | 80 | public NonComparable(int me) { 81 | id = me; 82 | } 83 | 84 | public boolean equals(Object other) { 85 | return ((NonComparable) other).id == id; 86 | } 87 | 88 | public int hashCode() { 89 | return id; 90 | } 91 | } 92 | } 93 | --------------------------------------------------------------------------------