Permalink
Browse files

api for calculating the permutation parity of a sub-array

Signed-off-by: Egon Willighagen <egonw@users.sourceforge.net>
  • Loading branch information...
johnmay authored and egonw committed Feb 11, 2013
1 parent f3f10ce commit 920ad3e7e7e02b432e0bd637e3096e6f26441a98
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2013. John May <jwmay@users.sf.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* All we ask is that proper credit is given for our work, which includes
* - but is not limited to - adding the above copyright notice to the beginning
* of your source code files, and to any copyright notice that you may distribute
* with programs based on this work.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 U
*/
package org.openscience.cdk.hash.stereo.parity;
import org.openscience.cdk.annotations.TestClass;
import org.openscience.cdk.annotations.TestMethod;
/**
* A basic implementation suitable for determining the parity of the indicates a
* provided sub-array.
*
* @author John May
* @cdk.module hash
*/
@TestClass("org.openscience.cdk.hash.stereo.BasicPermutationParityTest")
public final class BasicPermutationParity implements PermutationParity {
private final int[] indices;
/**
* Create a permutation parity for the provided indices.
*
* @param indices sub-array of indices
* @throws NullPointerException the provided indices were null
* @throws IllegalArgumentException less then two indices provided
*/
@TestMethod("testConstruction_Null,testConstruction_Empty")
public BasicPermutationParity(int[] indices) {
if (indices == null)
throw new NullPointerException("no indices[] provided");
if (indices.length < 2)
throw new IllegalArgumentException("at least 2 incides required");
this.indices = indices;
}
/**
* The number values to check is typically small ({@literal < 5}) and thus
* we use brute-force to count the number of inversions.
*
* @inheritDoc
*/
@TestMethod("testParity_Even,testParity_Odd,testParity_Even_Negative," +
"testParity_Odd_Negative,testParity_All,testParity_Duplicate")
@Override public int parity(long[] current) {
int count = 0;
for (int i = 0, n = indices.length; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int cmp = compare(current[indices[i]], current[indices[j]]);
if (cmp == 0)
return 0;
else if (cmp > 0)
count++;
}
}
// value is odd, -1 or value is even +1
return Integer.lowestOneBit(count) == 1 ? -1 : +1;
}
// TODO is CDK on JDK 7? this can be replaced with Long.compare(long, long)
private static int compare(long a, long b) {
return a > b ? +1 : a < b ? -1 : 0;
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2013. John May <jwmay@users.sf.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* All we ask is that proper credit is given for our work, which includes
* - but is not limited to - adding the above copyright notice to the beginning
* of your source code files, and to any copyright notice that you may distribute
* with programs based on this work.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 U
*/
package org.openscience.cdk.hash.stereo.parity;
/**
* Calculate the permutation parity on a given array of current values.
*
* @author John May
* @cdk.module hash
* @see <a href="http://en.wikipedia.org/wiki/Parity_of_a_permutation">Parity of a Permutation, Wikipedia</a>
*/
public interface PermutationParity {
/**
* Calculate the permutation parity of a permutation on the current values.
* The inversion parity counts whether we need to do an odd or even number
* of swaps to put the values in sorted order. If the values contain
* duplicates then the parity is returned as 0.
*
* @param current current values of invariants
* @return -1, odd number of swaps, +1, even number of swaps, 0, contains
* duplicates
*/
public int parity(long[] current);
}
@@ -0,0 +1,104 @@
/*
* Copyright (c) 2013. John May <jwmay@users.sf.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* All we ask is that proper credit is given for our work, which includes
* - but is not limited to - adding the above copyright notice to the beginning
* of your source code files, and to any copyright notice that you may distribute
* with programs based on this work.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 U
*/
package org.openscience.cdk.hash.stereo;
import org.junit.Test;
import org.openscience.cdk.hash.stereo.parity.BasicPermutationParity;
import static junit.framework.Assert.assertEquals;
/**
* @author John May
* @cdk.module test-hash
*/
public class BasicPermutationParityTest {
BasicPermutationParity permutationParity = new BasicPermutationParity(new int[]{0, 1, 2, 3});
@Test(expected = NullPointerException.class)
public void testConstruction_Null() {
new BasicPermutationParity(null);
}
@Test(expected = IllegalArgumentException.class)
public void testConstruction_Empty() {
new BasicPermutationParity(new int[0]);
}
@Test
public void testParity_Even() throws Exception {
assertEquals(1, permutationParity.parity(new long[]{4, 3, 2, 1}));
}
@Test
public void testParity_Odd() throws Exception {
assertEquals(-1, permutationParity.parity(new long[]{4, 2, 3, 1}));
}
@Test
public void testParity_Even_Negative() throws Exception {
assertEquals(1, permutationParity.parity(new long[]{4, 3, -1, -2}));
}
@Test
public void testParity_Odd_Negative() throws Exception {
assertEquals(-1, permutationParity.parity(new long[]{4, -1, 3, -2}));
}
@Test
public void testParity_Duplicate() throws Exception {
assertEquals(0, permutationParity.parity(new long[]{4, 3, -1, -1}));
}
@Test
public void testParity_All() throws Exception {
assertEquals(1, permutationParity.parity(new long[]{1, 2, 3, 4}));
assertEquals(-1, permutationParity.parity(new long[]{2, 1, 3, 4}));
assertEquals(-1, permutationParity.parity(new long[]{1, 3, 2, 4}));
assertEquals(1, permutationParity.parity(new long[]{3, 1, 2, 4}));
assertEquals(1, permutationParity.parity(new long[]{2, 3, 1, 4}));
assertEquals(-1, permutationParity.parity(new long[]{3, 2, 1, 4}));
assertEquals(-1, permutationParity.parity(new long[]{1, 2, 4, 3}));
assertEquals(1, permutationParity.parity(new long[]{2, 1, 4, 3}));
assertEquals(1, permutationParity.parity(new long[]{1, 4, 2, 3}));
assertEquals(-1, permutationParity.parity(new long[]{4, 1, 2, 3}));
assertEquals(-1, permutationParity.parity(new long[]{2, 4, 1, 3}));
assertEquals(1, permutationParity.parity(new long[]{4, 2, 1, 3}));
assertEquals(1, permutationParity.parity(new long[]{1, 3, 4, 2}));
assertEquals(-1, permutationParity.parity(new long[]{3, 1, 4, 2}));
assertEquals(-1, permutationParity.parity(new long[]{1, 4, 3, 2}));
assertEquals(1, permutationParity.parity(new long[]{4, 1, 3, 2}));
assertEquals(1, permutationParity.parity(new long[]{3, 4, 1, 2}));
assertEquals(-1, permutationParity.parity(new long[]{4, 3, 1, 2}));
assertEquals(-1, permutationParity.parity(new long[]{2, 3, 4, 1}));
assertEquals(1, permutationParity.parity(new long[]{3, 2, 4, 1}));
assertEquals(1, permutationParity.parity(new long[]{2, 4, 3, 1}));
assertEquals(-1, permutationParity.parity(new long[]{4, 2, 3, 1}));
assertEquals(-1, permutationParity.parity(new long[]{3, 4, 2, 1}));
assertEquals(1, permutationParity.parity(new long[]{4, 3, 2, 1}));
}
}
@@ -30,6 +30,8 @@
import org.openscience.cdk.hash.XorshiftTest;
import org.openscience.cdk.hash.seed.BasicAtomEncoderTest;
import org.openscience.cdk.hash.seed.ConjugatedAtomEncoderTest;
import org.openscience.cdk.hash.stereo.BasicPermutationParityTest;
import org.openscience.cdk.hash.stereo.parity.BasicPermutationParity;
/**
* TestSuite for the CDK <code>hash</code> module.
@@ -45,7 +47,8 @@
AbstractHashGeneratorTest.class,
BasicAtomHashGeneratorTest.class,
BasicMoleculeHashGeneratorTest.class,
HashGeneratorMakerTest.class
HashGeneratorMakerTest.class,
BasicPermutationParityTest.class,
})
public class MhashTests {
}

0 comments on commit 920ad3e

Please sign in to comment.