Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions base/core/src/main/java/org/openscience/cdk/graph/Cycles.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@
import org.openscience.cdk.interfaces.IRingSet;
import org.openscience.cdk.ringsearch.RingSearch;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Deque;
import java.util.List;

import static org.openscience.cdk.graph.GraphUtil.EdgeToBondMap;
Expand Down Expand Up @@ -410,6 +412,153 @@ public static CycleFinder allOrVertexShort() {
return or(all(), vertexShort());
}

/**
* Convenience method to determine the smallest ring size of every atom in
* the molecule. For each atom index the smallest ring size is set in the
* array, if 0 the atom is acyclic. If you just need to check a single atom
* is more efficient to call {@link #smallRingSize(IAtom, int)}.
*
* @param mol the molecule
* @param rsizes the array to be filled
* @see #smallRingSize(IAtom, int)
*/
public static void smallRingSizes(IAtomContainer mol, int[] rsizes)
{
int acount = mol.getAtomCount();
int marker = acount+1;
if (rsizes == null || acount > rsizes.length)
throw new IllegalArgumentException();
Arrays.fill(rsizes, 0, acount, marker);
Cycles cycles = Cycles.vertexShort(mol);
for (int[] path : cycles.paths()) {
int rsize = path.length-1;
for (int v : path) {
rsizes[v] = Math.min(rsize, rsizes[v]);
}
}
// replace temporary marker values with '0'
for (int i = 0; i < acount; i++) {
if (rsizes[i] == marker)
rsizes[i] = 0;
}
}

/**
* Determine the smallest ring size an atom belongs to. This method requires
* that {@link #markRingAtomsAndBonds(IAtomContainer)} has been called
* first to set the {@link IAtom#isInRing()} status of each atom/bond. If
* you need to check every atom in a molecule use
* {@link @see #smallRingSizes(IAtomContainer, int[])}.
*
* @param atom the atom
* @param max the max ring size
* @return the ring size, or 0 if the atom is not in a ring or is in a ring
* larger than 'max'
* @see #smallRingSizes(IAtomContainer, int[])
*/
public static int smallRingSize(IAtom atom, int max) {
if (!atom.isInRing())
return 0;
IAtomContainer mol = atom.getContainer();
int[] distTo = new int[mol.getAtomCount()];
Arrays.fill(distTo, 1 + distTo.length);
distTo[atom.getIndex()] = 0;
Deque<IAtom> queue = new ArrayDeque<>();
queue.add(atom);
int smallest = 1 + distTo.length;
while (!queue.isEmpty()) {
IAtom a = queue.poll();
int dist = 1 + distTo[a.getIndex()];
for (IBond b : a.bonds()) {
if (!b.isInRing())
continue;
IAtom nbr = b.getOther(a);
if (dist < distTo[nbr.getIndex()]) {
distTo[nbr.getIndex()] = dist;
queue.add(nbr);
} else if (dist != 2 + distTo[nbr.getIndex()]) {
int tmp = dist + distTo[nbr.getIndex()];
if (tmp < smallest)
smallest = tmp;
}
}
if (2 * dist > 1 + max)
break;
}
return smallest <= max ? smallest : 0;
}

/**
* Determine the smallest ring size an atom belongs to. This method requires
* that {@link #markRingAtomsAndBonds(IAtomContainer)} has been called
* first to set the {@link IAtom#isInRing()} status of each atom/bond. If
* you need to check every atom in a molecule use
* {@link @see #smallRingSizes(IAtomContainer, int[])}.
*
* @param atom the atom
* @return the ring size, or 0 if the atom is not in a ring
* @see #smallRingSizes(IAtomContainer, int[])
*/
public static int smallRingSize(IAtom atom) {
return smallRingSize(atom, atom.getContainer().getAtomCount());
}

/**
* Determine the smallest ring size an bond belongs to. This method requires
* that {@link #markRingAtomsAndBonds(IAtomContainer)} has been called
* first to set the {@link IBond#isInRing()} status of each atom/bond.
*
* @param bond the bond
* @param max the max ring size
* @return the ring size, or 0 if the bond is not in a ring or is in a ring
* larger than 'max'
*/
public static int smallRingSize(IBond bond, int max) {
if (!bond.isInRing())
return 0;
IAtomContainer mol = bond.getContainer();
int[] distTo = new int[mol.getAtomCount()];
Arrays.fill(distTo, 1 + distTo.length);
distTo[bond.getBegin().getIndex()] = 0;
distTo[bond.getEnd().getIndex()] = 0;
Deque<IAtom> queue = new ArrayDeque<>();
queue.add(bond.getBegin());
queue.add(bond.getEnd());
int smallest = 1 + distTo.length;
while (!queue.isEmpty()) {
IAtom a = queue.poll();
int dist = 1 + distTo[a.getIndex()];
for (IBond b : a.bonds()) {
if (b == bond || !b.isInRing())
continue;
IAtom nbr = b.getOther(a);
if (dist < distTo[nbr.getIndex()]) {
distTo[nbr.getIndex()] = dist;
queue.add(nbr);
} else if (dist != 2 + distTo[nbr.getIndex()]) {
int tmp = 1 + dist + distTo[nbr.getIndex()];
if (tmp < smallest)
smallest = tmp;
}
}
if (2 * dist > 1 + max)
break;
}
return smallest <= max ? smallest : 0;
}

/**
* Determine the smallest ring size an bond belongs to. This method requires
* that {@link #markRingAtomsAndBonds(IAtomContainer)} has been called
* first to set the {@link IBond#isInRing()} status of each atom/bond.
*
* @param bond the bond
* @return the ring size, or 0 if the bond is not in a ring or is in a ring
* larger than 'max'
*/
public static int smallRingSize(IBond bond) {
return smallRingSize(bond, bond.getContainer().getAtomCount());
}

/**
* Find and mark all cyclic atoms and bonds in the provided molecule.
Expand Down
136 changes: 136 additions & 0 deletions base/test-core/src/test/java/org/openscience/cdk/graph/CyclesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@

import org.junit.Test;
import org.openscience.cdk.AtomContainer;
import org.openscience.cdk.exception.InvalidSmilesException;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IRingSet;
import org.openscience.cdk.io.MDLV2000Reader;
import org.openscience.cdk.silent.SilentChemObjectBuilder;
import org.openscience.cdk.smiles.SmilesParser;
import org.openscience.cdk.templates.TestMoleculeFactory;

import java.util.Arrays;
import java.util.Iterator;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.openscience.cdk.templates.TestMoleculeFactory.makeAnthracene;
import static org.openscience.cdk.templates.TestMoleculeFactory.makeBicycloRings;
Expand Down Expand Up @@ -265,4 +270,135 @@ private IAtomContainer fullerene() throws Exception {
static void checkSize(Cycles cs, int nCycles) {
assertThat(cs.numberOfCycles(), is(nCycles));
}

private static IAtomContainer loadSmiles(String smi) throws InvalidSmilesException {
SmilesParser smipar = new SmilesParser(SilentChemObjectBuilder.getInstance());
IAtomContainer mol = smipar.parseSmiles(smi);
return mol;
}

private static void assertRingSizes(String smi, int ... expected) throws InvalidSmilesException {
SmilesParser smipar = new SmilesParser(SilentChemObjectBuilder.getInstance());
IAtomContainer mol = smipar.parseSmiles(smi);
Cycles.markRingAtomsAndBonds(mol);
int[] actual = new int[mol.getAtomCount()];
Cycles.smallRingSizes(mol, actual);
assertThat(Arrays.toString(actual), actual, is(expected));
}

@Test
public void testSmallRings() throws InvalidSmilesException {
assertRingSizes("C1CCCCC1", 6, 6, 6, 6, 6, 6);
assertRingSizes("C1CCCC1", 5, 5, 5, 5, 5);
// spiro
assertRingSizes("C1CCCCC11CCCC1", 6, 6, 6, 6, 6, 5, 5, 5, 5, 5);
// fused
assertRingSizes("CCC12CCC2CCCC1", 0, 0, 4, 4, 4, 4, 6, 6, 6, 6);
assertRingSizes("[nH]1ccc2c1cccc2", 5, 5, 5, 5, 5, 6, 6, 6, 6);
// compound
assertRingSizes("Clc4cccc(N3CCN(CCCCOc2ccc1c(NC(=O)CC1)c2)CC3)c4Cl",
0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 0);
}

@Test
public void testSmallRing_atom_simple() throws InvalidSmilesException {
IAtomContainer mol = loadSmiles("C1CCCCC1");
Cycles.markRingAtomsAndBonds(mol); // required
assertEquals(6,Cycles.smallRingSize(mol.getAtom(0)));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(2)));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(5)));

assertEquals(0,Cycles.smallRingSize(mol.getAtom(0), 4));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(2), 4));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(5), 4));

assertEquals(6,Cycles.smallRingSize(mol.getAtom(0), 6));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(2), 6));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(5), 6));

assertEquals(6,Cycles.smallRingSize(mol.getAtom(0), 7));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(2), 7));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(5), 7));
}

@Test
public void testSmallRing_atom_acyclic() throws InvalidSmilesException {
IAtomContainer mol = loadSmiles("CCCC");
Cycles.markRingAtomsAndBonds(mol); // required
assertEquals(0,Cycles.smallRingSize(mol.getAtom(0)));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(1)));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(2)));
}

@Test
public void testSmallRing_atom_indole() throws InvalidSmilesException {
IAtomContainer mol = loadSmiles("[nH]1ccc2c1cccc2");
Cycles.markRingAtomsAndBonds(mol); // required
assertEquals(5,Cycles.smallRingSize(mol.getAtom(0)));
assertEquals(5,Cycles.smallRingSize(mol.getAtom(1)));
assertEquals(5,Cycles.smallRingSize(mol.getAtom(2)));
assertEquals(5,Cycles.smallRingSize(mol.getAtom(3)));
assertEquals(5,Cycles.smallRingSize(mol.getAtom(4)));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(5)));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(6)));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(7)));
assertEquals(6,Cycles.smallRingSize(mol.getAtom(8)));
}

@Test
public void testSmallRing_atom_indole_lim() throws InvalidSmilesException {
IAtomContainer mol = loadSmiles("[nH]1ccc2c1cccc2");
Cycles.markRingAtomsAndBonds(mol); // required
assertEquals(5,Cycles.smallRingSize(mol.getAtom(0), 5));
assertEquals(5,Cycles.smallRingSize(mol.getAtom(1), 5));
assertEquals(5,Cycles.smallRingSize(mol.getAtom(2), 5));
assertEquals(5,Cycles.smallRingSize(mol.getAtom(3), 5));
assertEquals(5,Cycles.smallRingSize(mol.getAtom(4), 5));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(5), 5));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(6), 5));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(7), 5));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(8), 5));
// limit = 4
assertEquals(0,Cycles.smallRingSize(mol.getAtom(0), 4));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(1), 4));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(2), 4));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(3), 4));
assertEquals(0,Cycles.smallRingSize(mol.getAtom(4), 4));
}

@Test
public void testSmallRing_bond_indole() throws InvalidSmilesException {
IAtomContainer mol = loadSmiles("[nH]1ccc2c1cccc2");
Cycles.markRingAtomsAndBonds(mol); // required
assertEquals(5,Cycles.smallRingSize(mol.getBond(0)));
assertEquals(5,Cycles.smallRingSize(mol.getBond(1)));
assertEquals(5,Cycles.smallRingSize(mol.getBond(2)));
assertEquals(5,Cycles.smallRingSize(mol.getBond(3)));
assertEquals(5,Cycles.smallRingSize(mol.getBond(4)));
assertEquals(6,Cycles.smallRingSize(mol.getBond(5)));
assertEquals(6,Cycles.smallRingSize(mol.getBond(6)));
assertEquals(6,Cycles.smallRingSize(mol.getBond(7)));
assertEquals(6,Cycles.smallRingSize(mol.getBond(8)));
}

@Test
public void testSmallRing_bond_spiro() throws InvalidSmilesException {
IAtomContainer mol = loadSmiles("C1CCCC11CCC1");
Cycles.markRingAtomsAndBonds(mol); // required
assertEquals(5,Cycles.smallRingSize(mol.getBond(0)));
assertEquals(5,Cycles.smallRingSize(mol.getBond(1)));
assertEquals(5,Cycles.smallRingSize(mol.getBond(2)));
assertEquals(5,Cycles.smallRingSize(mol.getBond(3)));
assertEquals(5,Cycles.smallRingSize(mol.getBond(4)));
assertEquals(4,Cycles.smallRingSize(mol.getBond(5)));
assertEquals(4,Cycles.smallRingSize(mol.getBond(6)));
assertEquals(4,Cycles.smallRingSize(mol.getBond(7)));
assertEquals(4,Cycles.smallRingSize(mol.getBond(8)));
// limit=4
assertEquals(0,Cycles.smallRingSize(mol.getBond(3),4));
assertEquals(4,Cycles.smallRingSize(mol.getBond(7),4));
// limit=3
assertEquals(0,Cycles.smallRingSize(mol.getBond(3),3));
assertEquals(0,Cycles.smallRingSize(mol.getBond(7),3));
}
}