diff --git a/.classpath b/.classpath
index 133665b3a4f..97f7aee394f 100644
--- a/.classpath
+++ b/.classpath
@@ -1,6 +1,5 @@
-
@@ -18,7 +17,8 @@
-
+
+
diff --git a/jar/signatures-1.0-SNAPSHOT.jar b/jar/signatures-1.0-SNAPSHOT.jar
new file mode 100644
index 00000000000..8b23e7bed27
Binary files /dev/null and b/jar/signatures-1.0-SNAPSHOT.jar differ
diff --git a/src/main/org/openscience/cdk/signature/AtomSignature.java b/src/main/org/openscience/cdk/signature/AtomSignature.java
new file mode 100644
index 00000000000..fee5290dc73
--- /dev/null
+++ b/src/main/org/openscience/cdk/signature/AtomSignature.java
@@ -0,0 +1,120 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import java.util.List;
+
+import org.openscience.cdk.annotations.TestClass;
+import org.openscience.cdk.interfaces.IAtom;
+import org.openscience.cdk.interfaces.IAtomContainer;
+import org.openscience.cdk.interfaces.IBond;
+
+import signature.AbstractVertexSignature;
+
+/**
+ * The signature for a molecule rooted at a particular atom.
+ *
+ * @cdk.module signature
+ * @author maclean
+ *
+ */
+@TestClass("org.openscience.cdk.signature.AtomSignatureTest")
+public class AtomSignature extends AbstractVertexSignature {
+
+ /**
+ * The atom container to make signatures from
+ */
+ private IAtomContainer molecule;
+
+ /**
+ * Create an atom signature starting at atomIndex
.
+ *
+ * @param atomIndex the index of the atom that roots this signature
+ * @param molecule the molecule to create the signature from
+ */
+ public AtomSignature(int atomIndex, IAtomContainer molecule) {
+ super();
+ this.molecule = molecule;
+ super.createMaximumHeight(atomIndex, molecule.getAtomCount());
+ }
+
+ /**
+ * Create an atom signature starting at atomIndex
and with a
+ * maximum height of h
.
+ *
+ * @param atomIndex the index of the atom that roots this signature
+ * @param height the maximum height of the signature
+ * @param molecule the molecule to create the signature from
+ */
+ public AtomSignature(int atomIndex, int height, IAtomContainer molecule) {
+ super();
+ this.molecule = molecule;
+ super.create(atomIndex, molecule.getAtomCount(), height);
+ }
+
+ /* (non-Javadoc)
+ * @see signature.AbstractVertexSignature#getConnected(int)
+ */
+ @Override
+ public int[] getConnected(int vertexIndex) {
+ IAtom atom = this.molecule.getAtom(vertexIndex);
+ List connected = this.molecule.getConnectedAtomsList(atom);
+ int[] connectedIndices = new int[connected.size()];
+ int i = 0;
+ for (IAtom otherAtom : connected) {
+ connectedIndices[i++] = this.molecule.getAtomNumber(otherAtom);
+ }
+ return connectedIndices;
+ }
+
+ /* (non-Javadoc)
+ * @see signature.AbstractVertexSignature#getEdgeLabel(int, int)
+ */
+ @Override
+ public String getEdgeLabel(int vertexIndex, int otherVertexIndex) {
+ IAtom atomA = this.molecule.getAtom(vertexIndex);
+ IAtom atomB = this.molecule.getAtom(otherVertexIndex);
+ IBond bond = this.molecule.getBond(atomA, atomB);
+ if (bond != null) {
+ switch (bond.getOrder()) {
+// case SINGLE: return "-";
+ case SINGLE: return "";
+ case DOUBLE: return "=";
+ case TRIPLE: return "#";
+ case QUADRUPLE: return "$";
+ default: return "";
+ }
+ } else {
+ return "";
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see signature.AbstractVertexSignature#getVertexSymbol(int)
+ */
+ @Override
+ public String getVertexSymbol(int vertexIndex) {
+ return this.molecule.getAtom(vertexIndex).getSymbol();
+ }
+
+}
diff --git a/src/main/org/openscience/cdk/signature/MoleculeFromSignatureBuilder.java b/src/main/org/openscience/cdk/signature/MoleculeFromSignatureBuilder.java
new file mode 100644
index 00000000000..2c912fdbe02
--- /dev/null
+++ b/src/main/org/openscience/cdk/signature/MoleculeFromSignatureBuilder.java
@@ -0,0 +1,110 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import org.openscience.cdk.annotations.TestClass;
+import org.openscience.cdk.interfaces.IAtom;
+import org.openscience.cdk.interfaces.IAtomContainer;
+import org.openscience.cdk.interfaces.IBond;
+import org.openscience.cdk.interfaces.IChemObjectBuilder;
+import org.openscience.cdk.nonotify.NoNotificationChemObjectBuilder;
+
+import signature.AbstractGraphBuilder;
+
+/**
+ * Builds a molecule from a signature.
+ *
+ * @cdk.module signature
+ * @author maclean
+ *
+ */
+@TestClass("org.openscience.cdk.signature.MoleculeFromSignatureBuilderTest")
+public class MoleculeFromSignatureBuilder extends AbstractGraphBuilder {
+
+ /**
+ * The chem object builder
+ */
+ private IChemObjectBuilder builder;
+
+ /**
+ * The container that is being constructed
+ */
+ private IAtomContainer container;
+
+ /**
+ * This default constructor uses a {@link NoNotificationChemObjectBuilder}
+ */
+ public MoleculeFromSignatureBuilder() {
+ this.builder = NoNotificationChemObjectBuilder.getInstance();
+ }
+
+ /**
+ * Uses the chem object builder for making molecules.
+ *
+ * @param builder a builder for CDK molecules.
+ */
+ public MoleculeFromSignatureBuilder(IChemObjectBuilder builder) {
+ this.builder = builder;
+ }
+
+ /* (non-Javadoc)
+ * @see signature.AbstractGraphBuilder#makeEdge(int, int, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public void makeEdge(int vertexIndex1, int vertexIndex2,
+ String vertexSymbol1, String vertexSymbol2, String edgeLabel) {
+ if (edgeLabel.equals("")) {
+ container.addBond(vertexIndex1, vertexIndex2, IBond.Order.SINGLE);
+ } else if (edgeLabel.equals("=")) {
+ container.addBond(vertexIndex1, vertexIndex2, IBond.Order.DOUBLE);
+ } else if (edgeLabel.equals("#")) {
+ container.addBond(vertexIndex1, vertexIndex2, IBond.Order.TRIPLE);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see signature.AbstractGraphBuilder#makeGraph()
+ */
+ @Override
+ public void makeGraph() {
+ this.container = this.builder.newInstance(IAtomContainer.class);
+ }
+
+ /* (non-Javadoc)
+ * @see signature.AbstractGraphBuilder#makeVertex(java.lang.String)
+ */
+ @Override
+ public void makeVertex(String label) {
+ this.container.addAtom(this.builder.newInstance(IAtom.class, label));
+ }
+
+ /**
+ * Gets the atom container.
+ *
+ * @return the constructed atom container
+ */
+ public IAtomContainer getAtomContainer() {
+ return this.container;
+ }
+
+}
diff --git a/src/main/org/openscience/cdk/signature/MoleculeSignature.java b/src/main/org/openscience/cdk/signature/MoleculeSignature.java
new file mode 100644
index 00000000000..738a15a8ea0
--- /dev/null
+++ b/src/main/org/openscience/cdk/signature/MoleculeSignature.java
@@ -0,0 +1,145 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openscience.cdk.annotations.TestClass;
+import org.openscience.cdk.interfaces.IAtomContainer;
+import org.openscience.cdk.interfaces.IMolecule;
+
+import signature.AbstractGraphSignature;
+import signature.AbstractVertexSignature;
+import signature.ColoredTree;
+import signature.SymmetryClass;
+
+/**
+ * A signature for an entire molecule.
+ *
+ * @cdk.module signature
+ * @author maclean
+ *
+ */
+@TestClass("org.openscience.cdk.signature.MoleculeSignatureTest")
+public class MoleculeSignature extends AbstractGraphSignature {
+
+ private IAtomContainer molecule;
+
+ /**
+ * Creates a signature that represents this molecule.
+ *
+ * @param molecule the molecule to convert to a signature
+ */
+ public MoleculeSignature(IAtomContainer molecule) {
+ super();
+ this.molecule = molecule;
+ }
+
+ /**
+ * Creates a signature with a maximum height of height
+ * for molecule molecule
.
+ *
+ * @param molecule the molecule to convert to a signature
+ * @param height the maximum height of the signature
+ */
+ public MoleculeSignature(IMolecule molecule, int height) {
+ super(height);
+ this.molecule = molecule;
+ }
+
+ @Override
+ public int getVertexCount() {
+ return this.molecule.getAtomCount();
+ }
+
+ @Override
+ public String signatureStringForVertex(int vertexIndex) {
+ AtomSignature atomSignature;
+ int height = super.getHeight();
+ if (height == -1) {
+ atomSignature = new AtomSignature(vertexIndex, this.molecule);
+ } else {
+ atomSignature =
+ new AtomSignature(vertexIndex, height, this.molecule);
+ }
+ return atomSignature.toCanonicalString();
+ }
+
+ @Override
+ public String signatureStringForVertex(int vertexIndex, int height) {
+ AtomSignature atomSignature =
+ new AtomSignature(vertexIndex, height, this.molecule);
+ return atomSignature.toCanonicalString();
+ }
+
+ @Override
+ public AbstractVertexSignature signatureForVertex(int vertexIndex) {
+ return new AtomSignature(vertexIndex, this.molecule);
+ }
+
+ /**
+ * Calculates the orbits of the atoms of the molecule.
+ *
+ * @return a list of orbits
+ */
+ public List calculateOrbits() {
+ List orbits = new ArrayList();
+ List symmetryClasses = super.getSymmetryClasses();
+ for (SymmetryClass symmetryClass : symmetryClasses) {
+ Orbit orbit = new Orbit(symmetryClass.getSignatureString(), -1);
+ for (int atomIndex : symmetryClass) {
+ orbit.addAtom(atomIndex);
+ }
+ orbits.add(orbit);
+ }
+ return orbits;
+ }
+
+ /**
+ * Builder for molecules (rather, for atom containers) from signature
+ * strings.
+ *
+ * @param signatureString the signature string to use
+ * @return an atom container
+ */
+ public static IAtomContainer fromSignatureString(String signatureString) {
+ ColoredTree tree = AtomSignature.parse(signatureString);
+ MoleculeFromSignatureBuilder builder =
+ new MoleculeFromSignatureBuilder();
+ builder.makeFromColoredTree(tree);
+ return builder.getAtomContainer();
+ }
+
+ public String toCanonicalSignatureString(int height) {
+ String canonicalSignature = null;
+ for (int i = 0; i < getVertexCount(); i++) {
+ String signatureForI = signatureStringForVertex(i, height);
+ if (canonicalSignature == null ||
+ canonicalSignature.compareTo(signatureForI) < 0) {
+ canonicalSignature = signatureForI;
+ }
+ }
+ return canonicalSignature;
+ }
+}
diff --git a/src/main/org/openscience/cdk/signature/Orbit.java b/src/main/org/openscience/cdk/signature/Orbit.java
new file mode 100644
index 00000000000..da6efc121ee
--- /dev/null
+++ b/src/main/org/openscience/cdk/signature/Orbit.java
@@ -0,0 +1,190 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.openscience.cdk.annotations.TestClass;
+import org.openscience.cdk.annotations.TestMethod;
+
+
+/**
+ * A list of atom indices, and the label of the orbit.
+ *
+ * @cdk.module signature
+ * @author maclean
+ *
+ */
+@TestClass("org.openscience.cdk.signature.OrbitTest")
+public class Orbit implements Iterable, Cloneable {
+
+ /**
+ * The atom indices in this orbit
+ */
+ private List atomIndices;
+
+ /**
+ * The label that all the atoms in the orbit share
+ */
+ private String label;
+
+ /**
+ * The maximum height of the signature string
+ */
+ private int height;
+
+ /**
+ * @param label
+ * @param height
+ */
+ public Orbit(String label, int height) {
+ this.label = label;
+ this.atomIndices = new ArrayList();
+ this.height = height;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Iterable#iterator()
+ */
+ public Iterator iterator() {
+ return this.atomIndices.iterator();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#clone()
+ */
+ public Object clone() {
+ Orbit o = new Orbit(this.label, this.height);
+ for (Integer i : this.atomIndices) {
+ o.atomIndices.add(new Integer(i));
+ }
+ return o;
+ }
+
+ /**
+ * Sorts the atom indices in this orbit
+ */
+ public void sort() {
+ // TODO : change the list to a sorted set?
+ Collections.sort(this.atomIndices);
+ }
+
+ /**
+ * Gets the height of the signature label.
+ *
+ * @return the height of the signature of this orbit
+ */
+ public int getHeight() {
+ return this.height;
+ }
+
+ /**
+ * Gets all the atom indices as a list.
+ *
+ * @return the atom indices
+ */
+ public List getAtomIndices() {
+ return this.atomIndices;
+ }
+
+ /**
+ * Adds an atom index to the orbit.
+ *
+ * @param atomIndex the atom index
+ */
+ public void addAtom(int atomIndex) {
+ this.atomIndices.add(atomIndex);
+ }
+
+ /**
+ * Checks to see if the orbit has this string as a label.
+ *
+ * @param otherLabel the label to compare with
+ * @return true if it has this label
+ */
+ public boolean hasLabel(String otherLabel) {
+ return this.label.equals(otherLabel);
+ }
+
+ /**
+ * Checks to see if the orbit is empty.
+ *
+ * @return true if there are no atom indices in the orbit
+ */
+ @TestMethod("isEmptyTest")
+ public boolean isEmpty() {
+ return this.atomIndices.isEmpty();
+ }
+
+ /**
+ * Gets the first atom index of the orbit.
+ *
+ * @return the first atom index
+ */
+ public int getFirstAtom() {
+ return this.atomIndices.get(0);
+ }
+
+ /**
+ * Removes an atom index from the orbit.
+ *
+ * @param atomIndex the atom index to remove
+ */
+ public void remove(int atomIndex) {
+ this.atomIndices.remove(this.atomIndices.indexOf(atomIndex));
+ }
+
+
+ /**
+ * Gets the label of the orbit.
+ *
+ * @return the orbit's string label
+ */
+ public String getLabel() {
+ return this.label;
+ }
+
+ /**
+ * Checks to see if the orbit contains this atom index.
+ *
+ * @param atomIndex the atom index to look for
+ * @return true if the orbit contains this atom index
+ */
+ @TestMethod("containsTest")
+ public boolean contains(int atomIndex) {
+ return this.atomIndices.contains(atomIndex);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return label + " " +
+ Arrays.deepToString(atomIndices.toArray());
+ }
+
+}
diff --git a/src/main/org/openscience/cdk/signature/SignatureQuotientGraph.java b/src/main/org/openscience/cdk/signature/SignatureQuotientGraph.java
new file mode 100644
index 00000000000..8dc872f9991
--- /dev/null
+++ b/src/main/org/openscience/cdk/signature/SignatureQuotientGraph.java
@@ -0,0 +1,86 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import org.openscience.cdk.annotations.TestClass;
+import org.openscience.cdk.interfaces.IAtom;
+import org.openscience.cdk.interfaces.IAtomContainer;
+
+import signature.AbstractQuotientGraph;
+
+/**
+ * A signature quotient graph has a vertex for every signature symmetry class
+ * and an edge for each bond in the molecule between atoms in their class.
+ *
+ * So a structure where all the atoms are in the same symmetry class will have a
+ * quotient graph with one vertex and one loop edge. At the other extreme, a
+ * structure where every atom is in a different class will have a quotient
+ * graph the same as the molecule.
+ *
+ * @cdk.module signature
+ * @author maclean
+ *
+ */
+@TestClass("org.openscience.cdk.signature.SignatureQuotientGraphTest")
+public class SignatureQuotientGraph extends AbstractQuotientGraph {
+
+ /**
+ * The atom container to work on
+ */
+ private IAtomContainer atomContainer;
+
+ /**
+ * Construct a quotient graph from the symmetry classes generated from the
+ * atom container.
+ *
+ * @param atomContainer the structure to use
+ */
+ public SignatureQuotientGraph(IAtomContainer atomContainer) {
+ this(atomContainer, -1);
+ }
+
+ /**
+ * Construct a quotient graph using symmetry classes defined by signatures
+ * of height height
.
+ *
+ * @param atomContainer the structure to use
+ * @param height the height of the signatures
+ */
+ public SignatureQuotientGraph(IAtomContainer atomContainer, int height) {
+ this.atomContainer = atomContainer;
+ MoleculeSignature moleculeSignature =
+ new MoleculeSignature(atomContainer);
+ super.construct(moleculeSignature.getSymmetryClasses(height));
+ }
+
+ /* (non-Javadoc)
+ * @see signature.AbstractQuotientGraph#isConnected(int, int)
+ */
+ @Override
+ public boolean isConnected(int i, int j) {
+ IAtom a = atomContainer.getAtom(i);
+ IAtom b = atomContainer.getAtom(j);
+ return atomContainer.getBond(a, b) != null;
+ }
+
+}
diff --git a/src/test/org/openscience/cdk/signature/AbstractSignatureTest.java b/src/test/org/openscience/cdk/signature/AbstractSignatureTest.java
new file mode 100644
index 00000000000..3ea10d0b795
--- /dev/null
+++ b/src/test/org/openscience/cdk/signature/AbstractSignatureTest.java
@@ -0,0 +1,434 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import org.openscience.cdk.CDKConstants;
+import org.openscience.cdk.interfaces.IAtom;
+import org.openscience.cdk.interfaces.IBond;
+import org.openscience.cdk.interfaces.IChemObjectBuilder;
+import org.openscience.cdk.interfaces.IMolecule;
+import org.openscience.cdk.nonotify.NoNotificationChemObjectBuilder;
+
+/**
+ * @cdk.module test-signature
+ * @author maclean
+ *
+ */
+public class AbstractSignatureTest {
+
+ public static IChemObjectBuilder builder =
+ NoNotificationChemObjectBuilder.getInstance();
+
+ public static void print(IMolecule mol) {
+ for (int i = 0; i < mol.getAtomCount(); i++) {
+ IAtom a = mol.getAtom(i);
+ System.out.print(a.getSymbol() + " " + i + " ");
+ }
+ System.out.println();
+ for (IBond bond : mol.bonds()) {
+ IAtom aa = bond.getAtom(0);
+ IAtom ab = bond.getAtom(1);
+ int o = bond.getOrder().ordinal() + 1;
+ int x = mol.getAtomNumber(aa);
+ int y = mol.getAtomNumber(ab);
+ if (x < y) {
+ System.out.print(x + "-" + y + "(" + o + "),");
+ } else {
+ System.out.print(y + "-" + x + "(" + o + "),");
+ }
+ }
+ }
+
+ public static void addHydrogens(IMolecule mol, int carbonIndex, int count) {
+ for (int i = 0; i < count; i++) {
+ mol.addAtom(builder.newInstance(IAtom.class, "H"));
+ int hydrogenIndex = mol.getAtomCount() - 1;
+ mol.addBond(carbonIndex, hydrogenIndex, IBond.Order.SINGLE);
+ }
+ }
+
+ public static void addCarbons(IMolecule mol, int count) {
+ for (int i = 0; i < count; i++) {
+ mol.addAtom(builder.newInstance(IAtom.class, "C"));
+ }
+ }
+
+ public static void addRing(int atomToAttachTo, int ringSize, IMolecule mol) {
+ int numberOfAtoms = mol.getAtomCount();
+ int previous = atomToAttachTo;
+ for (int i = 0; i < ringSize; i++) {
+ mol.addAtom(builder.newInstance(IAtom.class, "C"));
+ int current = numberOfAtoms + i;
+ mol.addBond(previous, current, IBond.Order.SINGLE);
+ previous = current;
+ }
+ mol.addBond(
+ numberOfAtoms, numberOfAtoms + (ringSize - 1), IBond.Order.SINGLE);
+ }
+
+ public static IMolecule makeRhLikeStructure(int pCount, int ringCount) {
+ IMolecule ttpr = builder.newInstance(IMolecule.class);
+ ttpr.addAtom(builder.newInstance(IAtom.class, "Rh"));
+ for (int i = 1; i <= pCount; i++) {
+ ttpr.addAtom(builder.newInstance(IAtom.class, "P"));
+ ttpr.addBond(0, i, IBond.Order.SINGLE);
+ }
+
+ for (int j = 1; j <= pCount; j++) {
+ for (int k = 0; k < ringCount; k++) {
+ AbstractSignatureTest.addRing(j, 6, ttpr);
+ }
+ }
+
+ return ttpr;
+ }
+
+ public static IMolecule makeCycleWheel(int ringSize, int ringCount) {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ mol.addAtom(builder.newInstance(IAtom.class, "C"));
+ for (int r = 0; r < ringCount; r++) {
+ AbstractSignatureTest.addRing(0, ringSize, mol);
+ }
+ return mol;
+ }
+
+ public static IMolecule makeSandwich(int ringSize, boolean hasMethyl) {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ AbstractSignatureTest.addCarbons(mol, (ringSize * 2));
+ mol.addAtom(builder.newInstance(IAtom.class, "Fe"));
+ int center = ringSize * 2;
+ // face A
+ for (int i = 0; i < ringSize - 1; i++) {
+ mol.addBond(i, i + 1, IBond.Order.SINGLE);
+ mol.addBond(i, center, IBond.Order.SINGLE);
+ }
+ mol.addBond(ringSize - 1, 0, IBond.Order.SINGLE);
+ mol.addBond(ringSize - 1, center, IBond.Order.SINGLE);
+
+// // face B
+ for (int i = 0; i < ringSize - 1; i++) {
+ mol.addBond(i + ringSize, i + ringSize + 1, IBond.Order.SINGLE);
+ mol.addBond(i + ringSize, center, IBond.Order.SINGLE);
+ }
+ mol.addBond((2 * ringSize) - 1, ringSize, IBond.Order.SINGLE);
+ mol.addBond((2 * ringSize) - 1, center, IBond.Order.SINGLE);
+
+ if (hasMethyl) {
+ mol.addAtom(builder.newInstance(IAtom.class, "C"));
+ mol.addBond(0, mol.getAtomCount() - 1, IBond.Order.SINGLE);
+ }
+
+ return mol;
+ }
+
+ public static IMolecule makeC7H16A() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ AbstractSignatureTest.addCarbons(mol, 7);
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+ mol.addBond(3, 5, IBond.Order.SINGLE);
+ mol.addBond(5, 6, IBond.Order.SINGLE);
+ AbstractSignatureTest.addHydrogens(mol, 0, 3);
+ AbstractSignatureTest.addHydrogens(mol, 1, 2);
+ AbstractSignatureTest.addHydrogens(mol, 2, 2);
+ AbstractSignatureTest.addHydrogens(mol, 3, 1);
+ AbstractSignatureTest.addHydrogens(mol, 4, 3);
+ AbstractSignatureTest.addHydrogens(mol, 5, 2);
+ AbstractSignatureTest.addHydrogens(mol, 6, 3);
+ return mol;
+ }
+
+ public static IMolecule makeC7H16B() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ AbstractSignatureTest.addCarbons(mol, 7);
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ mol.addBond(2, 5, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+ mol.addBond(5, 6, IBond.Order.SINGLE);
+ AbstractSignatureTest.addHydrogens(mol, 0, 3);
+ AbstractSignatureTest.addHydrogens(mol, 1, 2);
+ AbstractSignatureTest.addHydrogens(mol, 2, 1);
+ AbstractSignatureTest.addHydrogens(mol, 3, 2);
+ AbstractSignatureTest.addHydrogens(mol, 4, 3);
+ AbstractSignatureTest.addHydrogens(mol, 5, 2);
+ AbstractSignatureTest.addHydrogens(mol, 6, 3);
+ return mol;
+ }
+
+ public static IMolecule makeC7H16C() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ AbstractSignatureTest.addCarbons(mol, 7);
+ mol.addBond(0, 2, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+ mol.addBond(4, 5, IBond.Order.SINGLE);
+ mol.addBond(5, 6, IBond.Order.SINGLE);
+ AbstractSignatureTest.addHydrogens(mol, 0, 3);
+ AbstractSignatureTest.addHydrogens(mol, 1, 3);
+ AbstractSignatureTest.addHydrogens(mol, 2, 1);
+ AbstractSignatureTest.addHydrogens(mol, 3, 2);
+ AbstractSignatureTest.addHydrogens(mol, 4, 2);
+ AbstractSignatureTest.addHydrogens(mol, 5, 2);
+ AbstractSignatureTest.addHydrogens(mol, 6, 3);
+ return mol;
+ }
+
+ public static IMolecule makeDodecahedrane() {
+ IMolecule dodec = builder.newInstance(IMolecule.class);
+ for (int i = 0; i < 20; i++) {
+ dodec.addAtom(builder.newInstance(IAtom.class, "C"));
+ }
+ dodec.addBond(0, 1, IBond.Order.SINGLE);
+ dodec.addBond(0, 4, IBond.Order.SINGLE);
+ dodec.addBond(0, 5, IBond.Order.SINGLE);
+ dodec.addBond(1, 2, IBond.Order.SINGLE);
+ dodec.addBond(1, 6, IBond.Order.SINGLE);
+ dodec.addBond(2, 3, IBond.Order.SINGLE);
+ dodec.addBond(2, 7, IBond.Order.SINGLE);
+ dodec.addBond(3, 4, IBond.Order.SINGLE);
+ dodec.addBond(3, 8, IBond.Order.SINGLE);
+ dodec.addBond(4, 9, IBond.Order.SINGLE);
+ dodec.addBond(5, 10, IBond.Order.SINGLE);
+ dodec.addBond(5, 14, IBond.Order.SINGLE);
+ dodec.addBond(6, 10, IBond.Order.SINGLE);
+ dodec.addBond(6, 11, IBond.Order.SINGLE);
+ dodec.addBond(7, 11, IBond.Order.SINGLE);
+ dodec.addBond(7, 12, IBond.Order.SINGLE);
+ dodec.addBond(8, 12, IBond.Order.SINGLE);
+ dodec.addBond(8, 13, IBond.Order.SINGLE);
+ dodec.addBond(9, 13, IBond.Order.SINGLE);
+ dodec.addBond(9, 14, IBond.Order.SINGLE);
+ dodec.addBond(10, 16, IBond.Order.SINGLE);
+ dodec.addBond(11, 17, IBond.Order.SINGLE);
+ dodec.addBond(12, 18, IBond.Order.SINGLE);
+ dodec.addBond(13, 19, IBond.Order.SINGLE);
+ dodec.addBond(14, 15, IBond.Order.SINGLE);
+ dodec.addBond(15, 16, IBond.Order.SINGLE);
+ dodec.addBond(15, 19, IBond.Order.SINGLE);
+ dodec.addBond(16, 17, IBond.Order.SINGLE);
+ dodec.addBond(17, 18, IBond.Order.SINGLE);
+ dodec.addBond(18, 19, IBond.Order.SINGLE);
+
+ return dodec;
+ }
+
+ public static IMolecule makeCage() {
+ /*
+ * This 'molecule' is the example used to illustrate the
+ * algorithm outlined in the 2004 Faulon &ct. paper
+ */
+ IMolecule cage = builder.newInstance(IMolecule.class);
+ for (int i = 0; i < 16; i++) {
+ cage.addAtom(builder.newInstance(IAtom.class, "C"));
+ }
+ cage.addBond(0, 1, IBond.Order.SINGLE);
+ cage.addBond(0, 3, IBond.Order.SINGLE);
+ cage.addBond(0, 4, IBond.Order.SINGLE);
+ cage.addBond(1, 2, IBond.Order.SINGLE);
+ cage.addBond(1, 6, IBond.Order.SINGLE);
+ cage.addBond(2, 3, IBond.Order.SINGLE);
+ cage.addBond(2, 8, IBond.Order.SINGLE);
+ cage.addBond(3, 10, IBond.Order.SINGLE);
+ cage.addBond(4, 5, IBond.Order.SINGLE);
+ cage.addBond(4, 11, IBond.Order.SINGLE);
+ cage.addBond(5, 6, IBond.Order.SINGLE);
+ cage.addBond(5, 12, IBond.Order.SINGLE);
+ cage.addBond(6, 7, IBond.Order.SINGLE);
+ cage.addBond(7, 8, IBond.Order.SINGLE);
+ cage.addBond(7, 13, IBond.Order.SINGLE);
+ cage.addBond(8, 9, IBond.Order.SINGLE);
+ cage.addBond(9, 10, IBond.Order.SINGLE);
+ cage.addBond(9, 14, IBond.Order.SINGLE);
+ cage.addBond(10, 11, IBond.Order.SINGLE);
+ cage.addBond(11, 15, IBond.Order.SINGLE);
+ cage.addBond(12, 13, IBond.Order.SINGLE);
+ cage.addBond(12, 15, IBond.Order.SINGLE);
+ cage.addBond(13, 14, IBond.Order.SINGLE);
+ cage.addBond(14, 15, IBond.Order.SINGLE);
+ return cage;
+ }
+
+ /**
+ * Strictly speaking, this is more like a cube than cubane, as it has no
+ * hydrogens.
+ *
+ * @return
+ */
+ public static IMolecule makeCubane() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ addCarbons(mol, 8);
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(0, 3, IBond.Order.SINGLE);
+ mol.addBond(0, 7, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(1, 6, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ mol.addBond(2, 5, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+ mol.addBond(4, 5, IBond.Order.SINGLE);
+ mol.addBond(4, 7, IBond.Order.SINGLE);
+ mol.addBond(5, 6, IBond.Order.SINGLE);
+ mol.addBond(6, 7, IBond.Order.SINGLE);
+ return mol;
+ }
+
+ public static IMolecule makeCuneane() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ addCarbons(mol, 8);
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(0, 3, IBond.Order.SINGLE);
+ mol.addBond(0, 5, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(1, 7, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ mol.addBond(2, 7, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+ mol.addBond(4, 5, IBond.Order.SINGLE);
+ mol.addBond(4, 6, IBond.Order.SINGLE);
+ mol.addBond(5, 6, IBond.Order.SINGLE);
+ mol.addBond(6, 7, IBond.Order.SINGLE);
+ return mol;
+ }
+
+ public static IMolecule makeCyclobutane() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ addCarbons(mol, 4);
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(0, 3, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ return mol;
+ }
+
+ public static IMolecule makeBridgedCyclobutane() {
+ IMolecule mol = AbstractSignatureTest.makeCyclobutane();
+ mol.addBond(0, 2, IBond.Order.SINGLE);
+ return mol;
+ }
+
+ public static IMolecule makeNapthalene() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ addCarbons(mol, 10);
+ for (IAtom atom : mol.atoms()) {
+ atom.setFlag(CDKConstants.ISAROMATIC, true);
+ }
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ mol.addBond(2, 7, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+ mol.addBond(4, 5, IBond.Order.SINGLE);
+ mol.addBond(5, 6, IBond.Order.SINGLE);
+ mol.addBond(6, 7, IBond.Order.SINGLE);
+ mol.addBond(7, 8, IBond.Order.SINGLE);
+ mol.addBond(8, 9, IBond.Order.SINGLE);
+ mol.addBond(9, 0, IBond.Order.SINGLE);
+ for (IBond bond : mol.bonds()) {
+ bond.setFlag(CDKConstants.ISAROMATIC, true);
+ }
+ return mol;
+ }
+
+ public static IMolecule makeHexane() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ addCarbons(mol, 6);
+
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+ mol.addBond(4, 5, IBond.Order.SINGLE);
+
+ return mol;
+ }
+
+ public static IMolecule makeTwistane() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ addCarbons(mol, 10);
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(0, 2, IBond.Order.SINGLE);
+ mol.addBond(1, 3, IBond.Order.SINGLE);
+ mol.addBond(1, 5, IBond.Order.SINGLE);
+ mol.addBond(2, 4, IBond.Order.SINGLE);
+ mol.addBond(2, 7, IBond.Order.SINGLE);
+ mol.addBond(3, 8, IBond.Order.SINGLE);
+ mol.addBond(3, 9, IBond.Order.SINGLE);
+ mol.addBond(4, 6, IBond.Order.SINGLE);
+ mol.addBond(4, 9, IBond.Order.SINGLE);
+ mol.addBond(5, 6, IBond.Order.SINGLE);
+ mol.addBond(7, 8, IBond.Order.SINGLE);
+ return mol;
+ }
+
+ public static IMolecule makeBenzene() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ addCarbons(mol, 6);
+ for (IAtom atom : mol.atoms()) {
+ atom.setFlag(CDKConstants.ISAROMATIC, true);
+ }
+
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(1, 2, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+ mol.addBond(4, 5, IBond.Order.SINGLE);
+ mol.addBond(5, 0, IBond.Order.SINGLE);
+ for (IBond bond : mol.bonds()) {
+ bond.setFlag(CDKConstants.ISAROMATIC, true);
+ }
+ return mol;
+ }
+
+ /**
+ * This may not be a real molecule, but it is a good, simple test.
+ * It is something like cyclobutane with a single carbon bridge across it,
+ * or propellane without one of its bonds (see makePropellane).
+ *
+ * @return
+ */
+ public static IMolecule makePseudoPropellane() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ addCarbons(mol, 5);
+
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(0, 2, IBond.Order.SINGLE);
+ mol.addBond(0, 3, IBond.Order.SINGLE);
+ mol.addBond(1, 4, IBond.Order.SINGLE);
+ mol.addBond(2, 4, IBond.Order.SINGLE);
+ mol.addBond(3, 4, IBond.Order.SINGLE);
+
+ return mol;
+ }
+
+ public static IMolecule makePropellane() {
+ IMolecule mol = AbstractSignatureTest.makePseudoPropellane();
+ mol.addBond(0, 4, IBond.Order.SINGLE);
+ return mol;
+ }
+
+}
diff --git a/src/test/org/openscience/cdk/signature/AtomSignatureTest.java b/src/test/org/openscience/cdk/signature/AtomSignatureTest.java
new file mode 100644
index 00000000000..2befbbd40ef
--- /dev/null
+++ b/src/test/org/openscience/cdk/signature/AtomSignatureTest.java
@@ -0,0 +1,130 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.openscience.cdk.interfaces.IAtom;
+import org.openscience.cdk.interfaces.IMolecule;
+import org.openscience.cdk.signature.AtomSignature;
+
+/**
+ * @cdk.module test-signature
+ * @author maclean
+ *
+ */
+public class AtomSignatureTest extends AbstractSignatureTest {
+
+ @Test
+ public void heightTest() {
+ IMolecule benzene = makeBenzene();
+ AtomSignature atomSignature = new AtomSignature(0, 1, benzene);
+ System.out.println(atomSignature.toCanonicalString());
+ }
+
+ @Test
+ public void cubaneHeightTest() {
+ IMolecule cubane = AbstractSignatureTest.makeCubane();
+ moleculeIsCarbon3Regular(cubane);
+ int height = 3;
+ AtomSignature atomSignature = new AtomSignature(0, height, cubane);
+ String canonicalString = atomSignature.toCanonicalString();
+ System.out.println(canonicalString);
+ }
+
+ @Test
+ public void cuneaneCubaneHeightTest() {
+ IMolecule cuneane = AbstractSignatureTest.makeCuneane();
+ IMolecule cubane = AbstractSignatureTest.makeCubane();
+ int height = 1;
+ AtomSignature cuneaneSignature = new AtomSignature(0, height, cuneane);
+ AtomSignature cubaneSignature = new AtomSignature(0, height, cubane);
+ String cuneaneSigString = cuneaneSignature.toCanonicalString();
+ String cubaneSigString = cubaneSignature.toCanonicalString();
+ System.out.println(cuneaneSigString);
+ System.out.println(cubaneSigString);
+ Assert.assertEquals(cuneaneSigString, cubaneSigString);
+ }
+
+ public void moleculeIsCarbon3Regular(IMolecule molecule) {
+ int i = 0;
+ for (IAtom a : molecule.atoms()) {
+ int count = 0;
+ for (IAtom connected : molecule.getConnectedAtomsList(a)) {
+ if (connected.getSymbol().equals("C")) {
+ count++;
+ }
+ }
+ Assert.assertEquals("Failed for atom " + i, 3, count);
+ i++;
+ }
+ }
+
+ @Test
+ public void dodecahedraneHeightTest() {
+ IMolecule dodecahedrane = AbstractSignatureTest.makeDodecahedrane();
+ moleculeIsCarbon3Regular(dodecahedrane);
+ int diameter = 5;
+ for (int height = 0; height <= diameter; height++) {
+ allEqualAtHeightTest(dodecahedrane, height);
+ }
+ }
+
+ @Test
+ public void allHeightsOfASymmetricGraphAreEqualTest() {
+ IMolecule cubane = makeCubane();
+ int diameter = 3;
+ for (int height = 0; height <= diameter; height++) {
+ allEqualAtHeightTest(cubane, height);
+ }
+ }
+
+ public void allEqualAtHeightTest(IMolecule molecule, int height) {
+ Map sigfreq = new HashMap();
+ for (int i = 0; i < molecule.getAtomCount(); i++) {
+ AtomSignature atomSignature = new AtomSignature(i, height, molecule);
+ String canonicalSignature = atomSignature.toCanonicalString();
+ if (sigfreq.containsKey(canonicalSignature)) {
+ sigfreq.put(canonicalSignature, sigfreq.get(canonicalSignature) + 1);
+ } else {
+ sigfreq.put(canonicalSignature, 1);
+ }
+// System.out.println(i + " " + canonicalSignature);
+ }
+// for (String key : sigfreq.keySet()) { System.out.println(key + " " + sigfreq.get(key));}
+ Assert.assertEquals(1, sigfreq.keySet().size());
+ }
+
+ @Test
+ public void testNonZeroRootForSubsignature() {
+ IMolecule cubane = makeCubane();
+ AtomSignature atomSignature = new AtomSignature(1, 2, cubane);
+ String canonicalSignature = atomSignature.toCanonicalString();
+ System.out.println(canonicalSignature);
+ }
+
+}
diff --git a/src/test/org/openscience/cdk/signature/MoleculeFromSignatureBuilderTest.java b/src/test/org/openscience/cdk/signature/MoleculeFromSignatureBuilderTest.java
new file mode 100644
index 00000000000..1ae8ad2a753
--- /dev/null
+++ b/src/test/org/openscience/cdk/signature/MoleculeFromSignatureBuilderTest.java
@@ -0,0 +1,32 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+/**
+ * @cdk.module test-signature
+ * @author maclean
+ *
+ */
+public class MoleculeFromSignatureBuilderTest {
+
+}
diff --git a/src/test/org/openscience/cdk/signature/MoleculeSignatureTest.java b/src/test/org/openscience/cdk/signature/MoleculeSignatureTest.java
new file mode 100644
index 00000000000..37ab7177eac
--- /dev/null
+++ b/src/test/org/openscience/cdk/signature/MoleculeSignatureTest.java
@@ -0,0 +1,529 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.openscience.cdk.DefaultChemObjectBuilder;
+import org.openscience.cdk.exception.InvalidSmilesException;
+import org.openscience.cdk.graph.AtomContainerAtomPermutor;
+import org.openscience.cdk.interfaces.IAtom;
+import org.openscience.cdk.interfaces.IAtomContainer;
+import org.openscience.cdk.interfaces.IBond;
+import org.openscience.cdk.interfaces.IChemObjectBuilder;
+import org.openscience.cdk.interfaces.IMolecule;
+import org.openscience.cdk.io.MDLWriter;
+import org.openscience.cdk.signature.MoleculeSignature;
+import org.openscience.cdk.signature.Orbit;
+import org.openscience.cdk.signature.SignatureQuotientGraph;
+import org.openscience.cdk.smiles.SmilesParser;
+import org.openscience.cdk.templates.MoleculeFactory;
+
+/**
+ * @cdk.module test-signature
+ * @author maclean
+ *
+ */
+public class MoleculeSignatureTest {
+
+ private SmilesParser parser;
+
+ private IChemObjectBuilder builder;
+
+ public MoleculeSignatureTest() {
+ this.parser = new SmilesParser(DefaultChemObjectBuilder.getInstance());
+ this.builder = DefaultChemObjectBuilder.getInstance();
+ }
+
+ public void toMolfileString(IMolecule mol) {
+ MDLWriter writer = new MDLWriter(System.out);
+ try {
+ writer.writeMolecule(mol);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void fullPermutationTest(IMolecule mol) {
+ AtomContainerAtomPermutor permutor = new AtomContainerAtomPermutor(mol);
+ String expected = new MoleculeSignature(mol).toCanonicalString();
+ System.out.println("canonical = " + expected);
+ int numberOfPermutationsTried = 0;
+ while (permutor.hasNext()) {
+ IAtomContainer permutation = permutor.next();
+ String actual =
+ new MoleculeSignature(permutation).toCanonicalString();
+ numberOfPermutationsTried++;
+ String msg = "Failed on permutation " + numberOfPermutationsTried;
+ Assert.assertEquals(msg, expected, actual);
+ }
+ }
+
+ public void randomPermutationTest(IMolecule mol) {
+ AtomContainerAtomPermutor permutor = new AtomContainerAtomPermutor(mol);
+ String expected = new MoleculeSignature(mol).toCanonicalString();
+ int numberOfPermutationsTried = 0;
+ while (permutor.hasNext()) {
+// IAtomContainer permutation = permutor.randomNext();
+// String actual =
+// new MoleculeSignature(permutation).toCanonicalString();
+ numberOfPermutationsTried++;
+// String msg = "Failed on permutation " + numberOfPermutationsTried;
+// Assert.assertEquals(msg, expected, actual);
+ }
+ System.out.println(expected);
+ System.out.println("Tried " + numberOfPermutationsTried);
+ }
+
+ public String canonicalStringFromSmiles(String smiles)
+ throws InvalidSmilesException {
+ IMolecule mol = parser.parseSmiles(smiles);
+ MoleculeSignature signature = new MoleculeSignature(mol);
+ return signature.toCanonicalString();
+ }
+
+ public String canonicalStringFromMolecule(IMolecule molecule) {
+ MoleculeSignature signature = new MoleculeSignature(molecule);
+// return signature.toCanonicalString();
+ return signature.getGraphSignature();
+ }
+
+ public String fullStringFromMolecule(IMolecule molecule) {
+ MoleculeSignature molSig = new MoleculeSignature(molecule);
+ return molSig.toFullString();
+ }
+
+ public List getAtomicSignatures(IMolecule molecule) {
+ MoleculeSignature signature = new MoleculeSignature(molecule);
+ return signature.getVertexSignatureStrings();
+ }
+
+ public void addHydrogens(IMolecule mol, IAtom atom, int n) {
+ for (int i = 0; i < n; i++) {
+ IAtom h = builder.newInstance(IAtom.class,"H");
+ mol.addAtom(h);
+ mol.addBond(builder.newInstance(IBond.class, atom, h));
+ }
+ }
+
+ @Test
+ public void testEmpty() throws Exception {
+ IMolecule mol = DefaultChemObjectBuilder.getInstance().newInstance(IMolecule.class);
+ MoleculeSignature signature = new MoleculeSignature(mol);
+ String signatureString = signature.toCanonicalString();
+ String expected = "";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+
+ @Test
+ public void testSingleNode() throws Exception {
+ String singleChild = "C";
+ String signatureString = this.canonicalStringFromSmiles(singleChild);
+ String expected = "[C]";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+
+ @Test
+ public void testSingleChild() throws Exception {
+ String singleChild = "CC";
+ String signatureString = this.canonicalStringFromSmiles(singleChild);
+ String expected = "[C]([C])";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+ @Test
+ public void testMultipleChildren() throws Exception {
+ String multipleChildren = "C(C)C";
+ String signatureString =
+ this.canonicalStringFromSmiles(multipleChildren);
+ String expected = "[C]([C]([C]))";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+ @Test
+ public void testThreeCycle() throws Exception {
+ String fourCycle = "C1CC1";
+ String signatureString = this.canonicalStringFromSmiles(fourCycle);
+ String expected = "[C]([C,2]([C,1])[C,1])";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+ @Test
+ public void testFourCycle() throws Exception {
+ String fourCycle = "C1CCC1";
+ String signatureString = this.canonicalStringFromSmiles(fourCycle);
+ String expected = "[C]([C]([C,1])[C]([C,1]))";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+ @Test
+ public void testMultipleFourCycles() throws Exception {
+ String bridgedRing = "C1C(C2)CC12";
+ String signatureString = this.canonicalStringFromSmiles(bridgedRing);
+ String expected = "[C]([C]([C,1])[C]([C,1])[C]([C,1]))";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+ @Test
+ public void testFiveCycle() throws Exception {
+ String fiveCycle = "C1CCCC1";
+ String signatureString = this.canonicalStringFromSmiles(fiveCycle);
+ String expected = "[C]([C]([C,2]([C,1]))[C]([C,1]))";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+ @Test
+ public void testMultipleFiveCycles() throws Exception {
+ String multipleFiveCycle = "C1C(CC2)CCC12";
+ String signatureString =
+ this.canonicalStringFromSmiles(multipleFiveCycle);
+ String expected = "[C]([C]([C]([C,1]))[C]([C]([C,1]))[C]([C,1]))";
+ Assert.assertEquals(expected, signatureString);
+ }
+
+ @Test
+ public void testSandwich() {
+ IMolecule sandwich = AbstractSignatureTest.makeSandwich(5, true);
+// IMolecule sandwich = AbstractSignatureTest.makeSandwich(5, false);
+// toMolfileString(sandwich);
+ randomPermutationTest(sandwich);
+ }
+
+ @Test
+ public void testCubane() {
+ String expected = "[C]([C]([C,4]([C,3])[C,2]([C,3]))[C]([C,4][C,1]" +
+ "([C,3]))[C]([C,1][C,2]))";
+ IMolecule mol = AbstractSignatureTest.makeCubane();
+ Assert.assertEquals(expected, this.canonicalStringFromMolecule(mol));
+ }
+
+ @Test
+ public void testCage() {
+ String expectedA = "[C]([C]([C]([C,5][C,4]([C,1]))[C]([C,6][C,4]))" +
+ "[C]([C,5]([C]([C,1][C,2]))[C]([C,2]([C,3])[C,7]))"+
+ "[C]([C,6]([C]([C,1][C,3]))[C,7]([C,3])))";
+ String expectedB = "[C]([C]([C]([C]([C,2]([C,1])[C,5])[C,6])[C,8]" +
+ "([C,5]([C,4])))[C]([C]([C,4]([C,1])[C,7])[C,8])" +
+ "[C]([C,6]([C]([C,3][C,2]))[C,7]([C,3]([C,1]))))";
+ IMolecule mol = AbstractSignatureTest.makeCage();
+ String signature = this.canonicalStringFromMolecule(mol);
+ Assert.assertEquals(expectedA, signature);
+ Assert.assertFalse(expectedB.equals(signature));
+ String fullSignature = fullStringFromMolecule(mol);
+ String fullExpected = "8" + expectedA + " + 8" + expectedB;
+// System.out.println(fullSignature);
+ Assert.assertEquals(fullExpected, fullSignature);
+ }
+
+ @Test
+ public void testPropellane() {
+ String expectedA = "[C]([C]([C,3])[C,2]([C,1][C,3])[C,2][C,1])";
+ String expectedB = "[C]([C]([C,1])[C]([C,1])[C]([C,1])[C,1])";
+ IMolecule mol = AbstractSignatureTest.makePropellane();
+ String signature = this.canonicalStringFromMolecule(mol);
+ Assert.assertEquals(expectedB, signature);
+ Assert.assertFalse(expectedA.equals(signature));
+ }
+
+ @Test
+ public void testBridgedCycloButane() {
+ String expected = "[C]([C]([C,1])[C]([C,1])[C,1])";
+ IMolecule mol = AbstractSignatureTest.makeBridgedCyclobutane();
+ String signature = this.canonicalStringFromMolecule(mol);
+ for (String atomicSignature : this.getAtomicSignatures(mol)) {
+ System.out.println(atomicSignature);
+ }
+ Assert.assertEquals(expected, signature);
+ }
+
+ @Test
+ public void testCageAtVariousHeights() {
+ IMolecule cage = AbstractSignatureTest.makeCage();
+ MoleculeSignature molSig;
+ molSig = new MoleculeSignature(cage, 2);
+ System.out.println(molSig.signatureStringForVertex(0, 2));
+ molSig = new MoleculeSignature(cage, 3);
+ System.out.println(molSig.signatureStringForVertex(0, 3));
+ }
+
+ @Test
+ public void testCyclohexaneWithHydrogens() {
+ IMolecule cyclohexane = MoleculeFactory.makeCyclohexane();
+ for (int i = 0; i < 6; i++) {
+ addHydrogens(cyclohexane, cyclohexane.getAtom(i), 2);
+ }
+ String expected = "[C]([C]([C]([C,1]([H][H])[H][H])[H][H])" +
+ "[C]([C]([C,1][H][H])[H][H])[H][H])";
+
+ String actual = this.canonicalStringFromMolecule(cyclohexane);
+ Assert.assertEquals(expected, actual);
+ }
+
+ public void testSmiles(String smiles) {
+ try {
+ IMolecule molecule = this.parser.parseSmiles(smiles);
+ MoleculeSignature sig = new MoleculeSignature(molecule);
+// System.out.println(sig.toFullString());
+ System.out.println(sig.toCanonicalString());
+ } catch (Exception e) {
+
+ }
+ }
+
+ @Test
+ public void testCuneane() {
+ String cuneaneSmiles = "C1C2C3CC4C1C4C23";
+ testSmiles(cuneaneSmiles);
+ }
+
+ @Test
+ public void testBenzeneWithDoubleBonds() {
+ IMolecule benzene = builder.newInstance(IMolecule.class);
+ AbstractSignatureTest.addCarbons(benzene, 6);
+ for (int i = 0; i < 6; i++) {
+ AbstractSignatureTest.addHydrogens(benzene, i, 1);
+ }
+ benzene.addBond(0, 1, IBond.Order.SINGLE);
+ benzene.addBond(1, 2, IBond.Order.DOUBLE);
+ benzene.addBond(2, 3, IBond.Order.SINGLE);
+ benzene.addBond(3, 4, IBond.Order.DOUBLE);
+ benzene.addBond(4, 5, IBond.Order.SINGLE);
+ benzene.addBond(5, 0, IBond.Order.DOUBLE);
+
+ MoleculeSignature signature = new MoleculeSignature(benzene);
+ String carbonSignature = signature.signatureStringForVertex(0);
+ for (int i = 1; i < 6; i++) {
+ String carbonSignatureI = signature.signatureStringForVertex(i);
+ Assert.assertEquals(carbonSignature, carbonSignatureI);
+ }
+ }
+
+ @Test
+ public void cyclobuteneTest() {
+ IMolecule cyclobutene = builder.newInstance(IMolecule.class);
+ AbstractSignatureTest.addCarbons(cyclobutene, 4);
+ cyclobutene.addBond(0, 1, IBond.Order.SINGLE);
+ cyclobutene.addBond(0, 2, IBond.Order.SINGLE);
+ cyclobutene.addBond(1, 3, IBond.Order.DOUBLE);
+ cyclobutene.addBond(2, 3, IBond.Order.SINGLE);
+// toMolfileString(cyclobutene);
+ randomPermutationTest(cyclobutene);
+// System.out.println(fullStringFromMolecule(cyclobutene));
+ }
+
+ @Test
+ public void methyleneCyclopropeneTest() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ AbstractSignatureTest.addCarbons(mol, 4);
+ AbstractSignatureTest.addHydrogens(mol, 1, 2);
+ AbstractSignatureTest.addHydrogens(mol, 2, 1);
+ AbstractSignatureTest.addHydrogens(mol, 3, 1);
+ mol.addBond(0, 1, IBond.Order.DOUBLE);
+ mol.addBond(0, 2, IBond.Order.SINGLE);
+ mol.addBond(0, 3, IBond.Order.SINGLE);
+ mol.addBond(2, 3, IBond.Order.DOUBLE);
+ MoleculeSignature molSig = new MoleculeSignature(mol);
+ for (int i = 0; i < 4; i++) {
+ String sigForIHeight2 = molSig.signatureStringForVertex(i, 2);
+ System.out.println(i + " " + sigForIHeight2);
+ }
+// AbstractSignatureTest.print(mol);
+// toMolfileString(mol);
+ }
+
+ @Test
+ public void fusedSquareMultipleBondTest() {
+ IMolecule mol = builder.newInstance(IMolecule.class);
+ AbstractSignatureTest.addCarbons(mol, 7);
+ mol.addBond(0, 1, IBond.Order.SINGLE);
+ mol.addBond(0, 2, IBond.Order.SINGLE);
+ mol.addBond(0, 3, IBond.Order.SINGLE);
+ mol.addBond(0, 4, IBond.Order.SINGLE);
+ mol.addBond(1, 5, IBond.Order.DOUBLE);
+ mol.addBond(2, 5, IBond.Order.SINGLE);
+ mol.addBond(3, 6, IBond.Order.SINGLE);
+ mol.addBond(4, 6, IBond.Order.DOUBLE);
+// toMolfileString(mol);
+// MoleculeSignature molSig = new MoleculeSignature(mol);
+// String sigFor0 = molSig.signatureStringForVertex(0);
+// System.out.println(sigFor0);
+ randomPermutationTest(mol);
+ }
+
+ @Test
+ public void testPolyPhenylMolecule() throws Exception {
+ String smiles = "C1=CC=C(C=C1)P(C2=CC=CC=C2)(C3=CC=CC=C3)[RhH]" +
+ "(P(C4=CC=CC=C4)(C5=CC=CC=C5)C6=CC=CC=C6)(P(C7=CC=CC=C7)" +
+ "(C8=CC=CC=C8)C9=CC=CC=C9)P(C%10=CC=CC=C%10)" +
+ "(C%11=CC=CC=C%11)C%12=CC=CC=C%12";
+// testSmiles(smiles);
+ IMolecule mol = parser.parseSmiles(smiles);
+ int rhIndex = 0;
+ for (int i = 0; i < mol.getAtomCount(); i++) {
+ if (mol.getAtom(i).getSymbol().equals("Rh")) {
+ rhIndex = i;
+ break;
+ }
+ }
+// System.out.println("rh index = " + rhIndex);
+ MoleculeSignature molSig = new MoleculeSignature(mol);
+ String signatureForRh = molSig.signatureStringForVertex(rhIndex);
+ System.out.println(signatureForRh);
+// toMolfileString(mol);
+ }
+
+ @Test
+ public void methylFerroceneTest() throws Exception {
+ String smiles = "CC12C3C4C5C1[Fe]23456789C%10C6C7C8C9%10";
+// testSmiles(smiles);
+ IMolecule mol = parser.parseSmiles(smiles);
+// toMolfileString(mol);
+ randomPermutationTest(mol);
+ }
+
+ @Test
+ public void threeMethylSulphanylPropanal() throws Exception {
+ String smiles = "O=CCCSC";
+ fullPermutationTest(parser.parseSmiles(smiles));
+ }
+
+ @Test
+ public void cycleWheelTest() {
+ IMolecule mol = AbstractSignatureTest.makeCycleWheel(3, 3);
+// AbstractSignatureTest.print(mol);
+// toMolfileString(mol);
+ MoleculeSignature molSig = new MoleculeSignature(mol);
+ String centralSignature = molSig.signatureStringForVertex(0);
+ System.out.println(centralSignature);
+// for (String signature : getAtomicSignatures(threeThreeWheel)) {
+// System.out.println(signature);
+// }
+ }
+
+ @Test
+ public void ttprTest() {
+ int phosphateCount = 3;
+ int ringCount = 3;
+ IMolecule ttpr =
+ AbstractSignatureTest.makeRhLikeStructure(phosphateCount, ringCount);
+// toMolfileString(ttpr);
+ MoleculeSignature molSig = new MoleculeSignature(ttpr);
+ String centralSignature = molSig.signatureStringForVertex(0);
+ System.out.println(centralSignature);
+ }
+
+ @Test
+ public void napthaleneSkeletonHeightTest() {
+ IMolecule napthalene = builder.newInstance(IMolecule.class);
+ for (int i = 0; i < 10; i++) {
+ napthalene.addAtom(builder.newInstance(IAtom.class,"C"));
+ }
+ napthalene.addBond(0, 1, IBond.Order.SINGLE);
+ napthalene.addBond(0, 5, IBond.Order.SINGLE);
+ napthalene.addBond(1, 2, IBond.Order.SINGLE);
+ napthalene.addBond(1, 6, IBond.Order.SINGLE);
+ napthalene.addBond(2, 3, IBond.Order.SINGLE);
+ napthalene.addBond(2, 9, IBond.Order.SINGLE);
+ napthalene.addBond(3, 4, IBond.Order.SINGLE);
+ napthalene.addBond(4, 5, IBond.Order.SINGLE);
+ napthalene.addBond(6, 7, IBond.Order.SINGLE);
+ napthalene.addBond(7, 8, IBond.Order.SINGLE);
+ napthalene.addBond(8, 9, IBond.Order.SINGLE);
+
+ MoleculeSignature molSig = new MoleculeSignature(napthalene);
+ int height = 2;
+ Map orbits = new HashMap();
+ for (int i = 0; i < napthalene.getAtomCount(); i++) {
+ String signatureString = molSig.signatureStringForVertex(i, height);
+ Orbit orbit;
+ if (orbits.containsKey(signatureString)) {
+ orbit = orbits.get(signatureString);
+ } else {
+ orbit = new Orbit(signatureString, height);
+ orbits.put(signatureString, orbit);
+ }
+ orbit.addAtom(i);
+ }
+// for (String key : orbits.keySet()) {
+// System.out.println(orbits.get(key));
+// }
+ Assert.assertEquals(3, orbits.size());
+ }
+
+ @Test
+ public void napthaleneWithDoubleBondsAndHydrogenHeightTest() {
+ IMolecule napthalene = builder.newInstance(IMolecule.class);
+ for (int i = 0; i < 10; i++) {
+ napthalene.addAtom(builder.newInstance(IAtom.class,"C"));
+ }
+ napthalene.addBond(0, 1, IBond.Order.SINGLE);
+ napthalene.addBond(0, 5, IBond.Order.DOUBLE);
+ napthalene.addBond(1, 2, IBond.Order.DOUBLE);
+ napthalene.addBond(1, 6, IBond.Order.SINGLE);
+ napthalene.addBond(2, 3, IBond.Order.SINGLE);
+ napthalene.addBond(2, 9, IBond.Order.SINGLE);
+ napthalene.addBond(3, 4, IBond.Order.DOUBLE);
+ napthalene.addBond(4, 5, IBond.Order.SINGLE);
+ napthalene.addBond(6, 7, IBond.Order.DOUBLE);
+ napthalene.addBond(7, 8, IBond.Order.SINGLE);
+ napthalene.addBond(8, 9, IBond.Order.DOUBLE);
+
+ napthalene.addAtom(builder.newInstance(IAtom.class,"H"));
+ napthalene.addBond(0, 10, IBond.Order.SINGLE);
+ napthalene.addAtom(builder.newInstance(IAtom.class,"H"));
+ napthalene.addBond(3, 11, IBond.Order.SINGLE);
+ napthalene.addAtom(builder.newInstance(IAtom.class,"H"));
+ napthalene.addBond(4, 12, IBond.Order.SINGLE);
+ napthalene.addAtom(builder.newInstance(IAtom.class,"H"));
+ napthalene.addBond(5, 13, IBond.Order.SINGLE);
+ napthalene.addAtom(builder.newInstance(IAtom.class,"H"));
+ napthalene.addBond(6, 14, IBond.Order.SINGLE);
+ napthalene.addAtom(builder.newInstance(IAtom.class,"H"));
+ napthalene.addBond(7, 15, IBond.Order.SINGLE);
+ napthalene.addAtom(builder.newInstance(IAtom.class,"H"));
+ napthalene.addBond(8, 16, IBond.Order.SINGLE);
+ napthalene.addAtom(builder.newInstance(IAtom.class,"H"));
+ napthalene.addBond(9, 17, IBond.Order.SINGLE);
+
+ int height = 2;
+// MoleculeSignature molSig = new MoleculeSignature(napthalene);
+// for (int i = 0; i < napthalene.getAtomCount(); i++) {
+// String sigString = molSig.signatureStringForVertex(i, height);
+// System.out.println(i + " " + sigString);
+// }
+ SignatureQuotientGraph mqg =
+ new SignatureQuotientGraph(napthalene, height);
+ System.out.println(mqg);
+
+ }
+}
diff --git a/src/test/org/openscience/cdk/signature/OrbitTest.java b/src/test/org/openscience/cdk/signature/OrbitTest.java
new file mode 100644
index 00000000000..b3605b6e129
--- /dev/null
+++ b/src/test/org/openscience/cdk/signature/OrbitTest.java
@@ -0,0 +1,79 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @cdk.module test-signature
+ * @author maclean
+ *
+ */
+public class OrbitTest {
+
+ private static Orbit orbit;
+
+ @Before
+ public void setUp() {
+
+ // make a test orbit instance, with a nonsense
+ // string label, and some number of 'indices'
+ String orbitLabel = "ORBIT";
+ int height = 2;
+ orbit = new Orbit(orbitLabel, height);
+ int[] atomIndices = new int[] {0, 1, 2, 3};
+ for (int atomIndex : atomIndices) {
+ orbit.addAtom(atomIndex);
+ }
+ }
+
+ @Test
+ public void isEmptyTest() {
+ Assert.assertFalse("The setUp method should have made an orbit with " +
+ "some indices in it", orbit.isEmpty());
+ List indices = new ArrayList();
+ for (int index : orbit) {
+ indices.add(index);
+ }
+ for (int index : indices) {
+ orbit.remove(index);
+ }
+ Assert.assertTrue("Orbit should now be empty", orbit.isEmpty());
+ }
+
+ @Test
+ public void containsTest() {
+ for (int index : orbit) {
+ Assert.assertTrue("Index " + index + " not in orbit",
+ orbit.contains(index));
+ }
+ }
+
+
+}
diff --git a/src/test/org/openscience/cdk/signature/SignatureQuotientGraphTest.java b/src/test/org/openscience/cdk/signature/SignatureQuotientGraphTest.java
new file mode 100644
index 00000000000..3458db463df
--- /dev/null
+++ b/src/test/org/openscience/cdk/signature/SignatureQuotientGraphTest.java
@@ -0,0 +1,96 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.openscience.cdk.interfaces.IMolecule;
+import org.openscience.cdk.signature.SignatureQuotientGraph;
+
+/**
+ * @cdk.module test-signature
+ * @author maclean
+ *
+ */
+public class SignatureQuotientGraphTest extends AbstractSignatureTest {
+
+ public void checkParameters(SignatureQuotientGraph qGraph,
+ int expectedVertexCount,
+ int expectedEdgeCount,
+ int expectedLoopEdgeCount) {
+ System.out.println(qGraph);
+ Assert.assertEquals(expectedVertexCount, qGraph.getVertexCount());
+ Assert.assertEquals(expectedEdgeCount, qGraph.getEdgeCount());
+ Assert.assertEquals(expectedLoopEdgeCount, qGraph.numberOfLoopEdges());
+ }
+
+ @Test
+ public void testCubane() {
+ IMolecule cubane = AbstractSignatureTest.makeCubane();
+ SignatureQuotientGraph qGraph = new SignatureQuotientGraph(cubane);
+ checkParameters(qGraph, 1, 1, 1);
+ }
+
+ @Test
+ public void testCuneaneAtHeight1() {
+ IMolecule cuneane = AbstractSignatureTest.makeCuneane();
+ SignatureQuotientGraph qGraph = new SignatureQuotientGraph(cuneane, 1);
+ checkParameters(qGraph, 1, 1, 1);
+ }
+
+ @Test
+ public void testCuneaneAtHeight2() {
+ IMolecule cuneane = AbstractSignatureTest.makeCuneane();
+ SignatureQuotientGraph qGraph = new SignatureQuotientGraph(cuneane, 2);
+ checkParameters(qGraph, 3, 5, 3);
+ }
+
+ @Test
+ public void testPropellane() {
+ IMolecule propellane = AbstractSignatureTest.makePropellane();
+ SignatureQuotientGraph qGraph = new SignatureQuotientGraph(propellane);
+ checkParameters(qGraph, 2, 2, 1);
+ }
+
+ @Test
+ public void testTwistane() {
+ IMolecule twistane = AbstractSignatureTest.makeTwistane();
+ SignatureQuotientGraph qGraph = new SignatureQuotientGraph(twistane);
+ checkParameters(qGraph, 3, 4, 2);
+ }
+
+ @Test
+ public void testC7H16Isomers() {
+ IMolecule c7H16A = AbstractSignatureTest.makeC7H16A();
+ IMolecule c7H16B = AbstractSignatureTest.makeC7H16B();
+ IMolecule c7H16C = AbstractSignatureTest.makeC7H16C();
+ SignatureQuotientGraph qGraphA = new SignatureQuotientGraph(c7H16A, 1);
+ SignatureQuotientGraph qGraphB = new SignatureQuotientGraph(c7H16B, 1);
+ SignatureQuotientGraph qGraphC = new SignatureQuotientGraph(c7H16C, 1);
+ checkParameters(qGraphA, 4, 7, 1);
+ checkParameters(qGraphB, 4, 5, 0);
+ checkParameters(qGraphC, 4, 7, 1);
+ }
+
+}
diff --git a/src/test/org/openscience/cdk/signature/SignatureSuite.java b/src/test/org/openscience/cdk/signature/SignatureSuite.java
new file mode 100644
index 00000000000..0a94c36a505
--- /dev/null
+++ b/src/test/org/openscience/cdk/signature/SignatureSuite.java
@@ -0,0 +1,63 @@
+/* Copyright (C) 2009-2010 maclean {gilleain.torrance@gmail.com}
+*
+* 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 USA.
+*/
+package org.openscience.cdk.signature;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+
+import org.junit.runners.Suite;
+
+/**
+ * @cdk.module test-signature
+ * @author maclean
+ *
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ org.openscience.cdk.signature.AtomSignatureTest.class,
+ org.openscience.cdk.signature.OrbitTest.class,
+ org.openscience.cdk.signature.MoleculeFromSignatureBuilderTest.class,
+ org.openscience.cdk.signature.MoleculeSignatureTest.class,
+ org.openscience.cdk.signature.SignatureQuotientGraphTest.class
+})
+public class SignatureSuite {
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+}