diff --git a/src/main/org/openscience/cdk/structgen/stochastic/PartialFilledStructureMerger.java b/src/main/org/openscience/cdk/structgen/stochastic/PartialFilledStructureMerger.java
index 0d362dff18e..2812cea71a7 100644
--- a/src/main/org/openscience/cdk/structgen/stochastic/PartialFilledStructureMerger.java
+++ b/src/main/org/openscience/cdk/structgen/stochastic/PartialFilledStructureMerger.java
@@ -25,37 +25,21 @@
package org.openscience.cdk.structgen.stochastic;
import org.openscience.cdk.exception.CDKException;
-import org.openscience.cdk.graph.ConnectivityChecker;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
+import org.openscience.cdk.interfaces.IAtomContainerSet;
import org.openscience.cdk.tools.ILoggingTool;
import org.openscience.cdk.tools.LoggingToolFactory;
import org.openscience.cdk.tools.SaturationChecker;
+import org.openscience.cdk.tools.manipulator.AtomContainerSetManipulator;
import org.openscience.cdk.tools.manipulator.BondManipulator;
/**
- * Randomly generates a single, connected, correctly bonded structure for
- * a given molecular formula.
- * To see it working run the graphical
- * test org.openscience.cdk.test.SingleStructureRandomGeneratorTest
- * and add more structures to the panel using the "More" button.
- * In order to use this class, use MFAnalyser to get an AtomContainer from
- * a molecular formula string.
- *
+ * Randomly generates a single, connected, correctly bonded structure from
+ * a number of fragments.
*
Assign hydrogen counts to each heavy atom. The hydrogens should not be
* in the atom pool but should be assigned implicitly to the heavy atoms in
* order to reduce computational cost.
- *
- *
Assign this AtomContainer to the
- * PartialFilledStructureMerger and retrieve a randomly generated, but correctly bonded
- * structure by using the generate() method. You can then repeatedly call
- * the generate() method in order to retrieve further structures.
- *
- *
Agenda:
- *
- * - add a method for randomly adding hydrogens to the atoms
- *
- add a seed for random generator for reproducability
- *
*
* @author steinbeck
* @cdk.created 2001-09-04
@@ -67,110 +51,111 @@ public class PartialFilledStructureMerger {
private ILoggingTool logger =
LoggingToolFactory.createLoggingTool(PartialFilledStructureMerger.class);
- IAtomContainer atomContainer;
SaturationChecker satCheck;
/**
* Constructor for the PartialFilledStructureMerger object.
*/
- public PartialFilledStructureMerger() throws java.lang.Exception
+ public PartialFilledStructureMerger()
{
satCheck = new SaturationChecker();
}
/**
- * Sets the AtomContainer attribute of the PartialFilledStructureMerger object
- *
- * @param gc The new AtomContainer value
+ * Randomly generates a single, connected, correctly bonded structure from
+ * a number of fragments.
+ *
+ * @param atomContainers The fragments to generate for. IMPORTANT: The AtomContainers in the set must be connected.
+ * If an AtomContainer is disconnected, the generated structure is not guaranteed to be connected.
+ * @return
+ * @throws CDKException
*/
- public void setAtomContainer(IAtomContainer gc)
- {
- this.atomContainer = gc;
- }
-
- public IAtomContainer getAtomContainer()
- {
- return this.atomContainer;
- }
-
- public IAtomContainer generate() throws CDKException
+ public IAtomContainerSet generate(IAtomContainerSet atomContainers) throws CDKException
{
- boolean structureFound = false;
- boolean bondFormed;
- double order;
- double max, cmax1, cmax2;
int iteration = 0;
- IAtom partner;
- IAtom atom;
- IAtomContainer backup = atomContainer.getBuilder().newAtomContainer(atomContainer);
+ boolean structureFound = false;
do
{
iteration++;
-
- atomContainer = backup;
- do
- {
- bondFormed = false;
- for (int f = 0; f < atomContainer.getAtomCount(); f++)
- {
- atom = atomContainer.getAtom(f);
-
- if (!satCheck.isSaturated(atom, atomContainer))
- {
- partner = getAnotherUnsaturatedNode(atom);
- if (partner != null)
+ boolean bondFormed;
+ do{
+ bondFormed=false;
+ for(IAtomContainer ac : atomContainers.atomContainers()){
+ for(IAtom atom : ac.atoms()){
+ if (!satCheck.isSaturated(atom, ac))
{
- cmax1 = satCheck.getCurrentMaxBondOrder(atom, atomContainer);
- cmax2 = satCheck.getCurrentMaxBondOrder(partner, atomContainer);
- max = Math.min(cmax1, cmax2);
- order = Math.min(Math.max(1.0, (double)Math.round(Math.random() * max)), 3.0);
- logger.debug("cmax1, cmax2, max, order: " + cmax1 + ", " + cmax2 + ", " + max + ", " + order);
-
- atomContainer.addBond(
- atomContainer.getBuilder().newBond(
- atom, partner, BondManipulator.createBondOrder(order)
- )
- );
- bondFormed = true;
- }
- }
+ IAtom partner = getAnotherUnsaturatedNode(atom, atomContainers);
+ if (partner != null)
+ {
+ IAtomContainer toadd = AtomContainerSetManipulator.getRelevantAtomContainer(atomContainers, partner);
+ double cmax1 = satCheck.getCurrentMaxBondOrder(atom, ac);
+ double cmax2 = satCheck.getCurrentMaxBondOrder(partner, toadd);
+ double max = Math.min(cmax1, cmax2);
+ double order = Math.min(Math.max(1.0, max), 3.0);//(double)Math.round(Math.random() * max)
+ logger.debug("cmax1, cmax2, max, order: " + cmax1 + ", " + cmax2 + ", " + max + ", " + order);
+ if(toadd!=ac){
+ atomContainers.removeAtomContainer(toadd);
+ ac.add(toadd);
+ }
+ ac.addBond(
+ ac.getBuilder().newBond(
+ atom, partner, BondManipulator.createBondOrder(order)
+ )
+ );
+ bondFormed = true;
+ }
+ }
+ }
}
- } while (bondFormed);
- if (ConnectivityChecker.isConnected(atomContainer) && satCheck.allSaturated(atomContainer))
+ }while(bondFormed);
+ if (atomContainers.getAtomContainerCount()==1 && satCheck.allSaturated(atomContainers.getAtomContainer(0)))
{
structureFound = true;
}
- } while (!structureFound && iteration < 300);
- System.out.println("Structure found after " + iteration + " iterations.");
- return atomContainer;
+ } while (!structureFound && iteration < 5);
+ if (atomContainers.getAtomContainerCount()==1 && satCheck.allSaturated(atomContainers.getAtomContainer(0)))
+ {
+ structureFound = true;
+ }
+ if(!structureFound)
+ throw new CDKException("Could not combine the fragments to combine a valid, satured structure");
+ return atomContainers;
}
/**
- * Gets the AnotherUnsaturatedNode attribute of the PartialFilledStructureMerger object
+ * Gets a randomly selected unsaturated atom from the set. If there are any, it will be from another
+ * container than exclusionAtom.
*
- * @return The AnotherUnsaturatedNode value
+ * @return The unsaturated atom.
*/
- private IAtom getAnotherUnsaturatedNode(IAtom exclusionAtom) throws CDKException
+ private IAtom getAnotherUnsaturatedNode(IAtom exclusionAtom, IAtomContainerSet atomContainers) throws CDKException
{
IAtom atom;
- int next = (int) (Math.random() * atomContainer.getAtomCount());
- for (int f = next; f < atomContainer.getAtomCount(); f++)
- {
- atom = atomContainer.getAtom(f);
- if (!satCheck.isSaturated(atom, atomContainer) && exclusionAtom != atom && !atomContainer.getConnectedAtomsList(exclusionAtom).contains(atom))
- {
- return atom;
+ for(IAtomContainer ac : atomContainers.atomContainers()){
+ if(!ac.contains(exclusionAtom)){
+ int next = 0;//(int) (Math.random() * ac.getAtomCount());
+ for (int f = next; f < ac.getAtomCount(); f++)
+ {
+ atom = ac.getAtom(f);
+ if (!satCheck.isSaturated(atom, ac) && exclusionAtom != atom && !ac.getConnectedAtomsList(exclusionAtom).contains(atom))
+ {
+ return atom;
+ }
+ }
}
}
- for (int f = 0; f < next; f++)
- {
- atom = atomContainer.getAtom(f);
- if (!satCheck.isSaturated(atom, atomContainer) && exclusionAtom != atom && !atomContainer.getConnectedAtomsList(exclusionAtom).contains(atom))
+ for(IAtomContainer ac : atomContainers.atomContainers()){
+ int next = ac.getAtomCount();//(int) (Math.random() * ac.getAtomCount());
+ for (int f = 0; f < next; f++)
{
- return atom;
+ atom = ac.getAtom(f);
+ if (!satCheck.isSaturated(atom, ac) && exclusionAtom != atom && !ac.getConnectedAtomsList(exclusionAtom).contains(atom))
+ {
+ return atom;
+ }
}
}
return null;
diff --git a/src/main/org/openscience/cdk/structgen/stochastic/operator/ChemGraph.java b/src/main/org/openscience/cdk/structgen/stochastic/operator/ChemGraph.java
index 89ec75b7d68..c839bd21d76 100644
--- a/src/main/org/openscience/cdk/structgen/stochastic/operator/ChemGraph.java
+++ b/src/main/org/openscience/cdk/structgen/stochastic/operator/ChemGraph.java
@@ -47,7 +47,7 @@ public class ChemGraph
/*Flag: true if atom visited during a traversal*/
protected boolean[] visited;
/*Depth first traversal of the graph*/
- protected List subGraph;
+ protected List subGraph;
public ChemGraph(IAtomContainer chrom)
{
@@ -57,12 +57,12 @@ public ChemGraph(IAtomContainer chrom)
contab = ConnectionMatrix.getMatrix(chrom);
}
- public List pickDFgraph()
+ public List pickDFgraph()
{
//depth first search from a randomly selected atom
travIndex = 0;
- subGraph = new ArrayList();
+ subGraph = new ArrayList();
visited = new boolean[dim];
for (int atom = 0; atom < dim; atom++) visited[atom] = false;
int seedAtom = RandomNumbersTool.randomInt(0,dim-1);
@@ -81,7 +81,7 @@ private void recursiveDFT(int atom)
// for (int nextAtom = 0; nextAtom < dim; nextAtom++) //not generalized
// if (contab[atom][nextAtom] != 0) recursiveDFT(nextAtom);
- List adjSet = new ArrayList();
+ List adjSet = new ArrayList();
for (int nextAtom = 0; nextAtom < dim; nextAtom++)
{
if ((int)contab[atom][nextAtom] != 0)
@@ -99,17 +99,17 @@ private void recursiveDFT(int atom)
}
}
- public List pickBFgraph()
+ public List pickBFgraph()
{
//breadth first search from a randomly selected atom
travIndex = 0;
- subGraph = new ArrayList();
+ subGraph = new ArrayList();
visited = new boolean[dim];
for (int atom = 0; atom < dim; atom++) visited[atom] = false;
int seedAtom = RandomNumbersTool.randomInt(0,dim-1);
- List atomQueue = new ArrayList();
+ List atomQueue = new ArrayList();
atomQueue.add(Integer.valueOf(seedAtom));
visited[seedAtom] = true;
@@ -120,7 +120,7 @@ public List pickBFgraph()
atomQueue.remove(0);
travIndex++;
- List adjSet = new ArrayList();
+ List adjSet = new ArrayList();
for (int nextAtom = 0; nextAtom < dim; nextAtom++)
{
if (((int)contab[foreAtom][nextAtom] != 0)&&(!visited[nextAtom]))
@@ -140,12 +140,12 @@ public List pickBFgraph()
return subGraph;
}
- public List getSubgraph()
+ public List getSubgraph()
{
return subGraph;
}
- public void setSubgraph(List subgraph)
+ public void setSubgraph(List subgraph)
{
subGraph = subgraph;
}
diff --git a/src/main/org/openscience/cdk/structgen/stochastic/operator/CrossoverMachine.java b/src/main/org/openscience/cdk/structgen/stochastic/operator/CrossoverMachine.java
index 654a27f5597..c28b7904542 100644
--- a/src/main/org/openscience/cdk/structgen/stochastic/operator/CrossoverMachine.java
+++ b/src/main/org/openscience/cdk/structgen/stochastic/operator/CrossoverMachine.java
@@ -21,14 +21,16 @@
package org.openscience.cdk.structgen.stochastic.operator;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import org.openscience.cdk.exception.CDKException;
+import org.openscience.cdk.graph.ConnectivityChecker;
+import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
-import org.openscience.cdk.interfaces.IBond;
+import org.openscience.cdk.interfaces.IAtomContainerSet;
import org.openscience.cdk.math.RandomNumbersTool;
import org.openscience.cdk.structgen.stochastic.PartialFilledStructureMerger;
+import org.openscience.cdk.tools.SaturationChecker;
/**
* Modified molecular structures by applying crossover operator on a pair of parent structures
@@ -40,10 +42,6 @@
*/
public class CrossoverMachine
{
- private IAtomContainer[] redChild,blueChild;
- private List redAtoms,blueAtoms;
- List children;
-
PartialFilledStructureMerger pfsm;
/** selects a partitioning mode*/
@@ -62,141 +60,165 @@ public class CrossoverMachine
*/
public CrossoverMachine()
{
- redChild = new IAtomContainer[2];
- blueChild = new IAtomContainer[2];
-
- redAtoms = new ArrayList();
- blueAtoms = new ArrayList();
- children = new ArrayList(2);
- try
- {
- pfsm = new PartialFilledStructureMerger();
- }
- catch(java.lang.Exception ex){ }
+ pfsm = new PartialFilledStructureMerger();
}
/**
- * Performs the n point crossover of two MolChromosome
- * supplied by the CrossInfo.parents
class and stores the resulting
- * chromosomes in CrossInfo.children
.
+ * Performs the n point crossover of two IAtomContainer
.
*
- * @return an object storing information generated by the operator.
- * @exception IllegalArgumentException if some of the crosspoints defined are
- * greater than the size of the corresponding chromosome.
+ * @return The children.
+ * @exception CDKException if it was not possible to form offsprings.
*/
- public List doCrossover(IAtomContainer dad, IAtomContainer mom) throws CDKException
+ public List doCrossover(IAtomContainer dad, IAtomContainer mom) throws CDKException
{
- int dim = dad.getAtomCount();
-
- /***randomly divide atoms into two parts: redAtoms and blueAtoms.***/
- redAtoms.clear();
- blueAtoms.clear();
-
- if (splitMode==SPLIT_MODE_RADNDOM)
- {
- /*better way to randomly divide atoms into two parts: redAtoms and blueAtoms.*/
- for (int i = 0; i < dim; i++)
- redAtoms.add(Integer.valueOf(i));
- for (int i = 0; i < (dim - numatoms); i++)
- { int ranInt = RandomNumbersTool.randomInt(0,redAtoms.size()-1);
- redAtoms.remove(ranInt);
- blueAtoms.add(Integer.valueOf(ranInt));
- }
-
- }
- else
- {
- /*split graph using depth/breadth first traverse*/
- ChemGraph graph = new ChemGraph(dad);
- graph.setNumAtoms(numatoms);
- if (splitMode==SPLIT_MODE_DEPTH_FIRST)
+ int tries=0;
+ while(true){
+ int dim = dad.getAtomCount();
+ IAtomContainer[] redChild = new IAtomContainer[2];
+ IAtomContainer[] blueChild = new IAtomContainer[2];
+
+ List redAtoms = new ArrayList();
+ List blueAtoms = new ArrayList();
+
+ /***randomly divide atoms into two parts: redAtoms and blueAtoms.***/
+ if (splitMode==SPLIT_MODE_RADNDOM)
{
- redAtoms = graph.pickDFgraph();
+ /*better way to randomly divide atoms into two parts: redAtoms and blueAtoms.*/
+ for (int i = 0; i < dim; i++)
+ redAtoms.add(Integer.valueOf(i));
+ for (int i = 0; i < (dim - numatoms); i++)
+ { int ranInt = RandomNumbersTool.randomInt(0,redAtoms.size()-1);
+ redAtoms.remove(Integer.valueOf(ranInt));
+ blueAtoms.add(Integer.valueOf(ranInt));
+ }
+
}
else
- redAtoms = graph.pickBFgraph();
-
- for (int i = 0; i < dim; i++){
- Integer element = Integer.valueOf(i);
- if (!(redAtoms.contains(element)))
- {
- blueAtoms.add(element);
- }
- }
- }
- /*** dividing over ***/
-
-
- redChild[0] = dad.getBuilder().newAtomContainer(dad);
- blueChild[0] = dad.getBuilder().newAtomContainer(dad);
- redChild[1] = dad.getBuilder().newAtomContainer(mom);
- blueChild[1] = dad.getBuilder().newAtomContainer(mom);
-
-
- for (int j = 0; j < blueAtoms.size(); j++)
- {
- Iterator bonds = redChild[1].bonds().iterator();
- while (bonds.hasNext()) {
- IBond bond = (IBond)bonds.next();
- if (bond.contains(redChild[0].getAtom(((Integer)blueAtoms.get(j)).intValue())))
+ {
+ /*split graph using depth/breadth first traverse*/
+ ChemGraph graph = new ChemGraph(dad);
+ graph.setNumAtoms(numatoms);
+ if (splitMode==SPLIT_MODE_DEPTH_FIRST)
{
- redChild[0].removeBond(bond);
+ redAtoms = graph.pickDFgraph();
}
- }
- }
-
-
- for (int j = 0; j < blueAtoms.size(); j++)
- {
- Iterator bonds = redChild[1].bonds().iterator();
- while (bonds.hasNext()) {
- IBond bond = (IBond)bonds.next();
- if (bond.contains(redChild[1].getAtom(((Integer)blueAtoms.get(j)).intValue())))
+ else
{
- bonds.remove(); // this removes it from redChild[1] too
+ //this is SPLIT_MODE_BREADTH_FIRST
+ redAtoms = graph.pickBFgraph();
+ }
+
+ for (int i = 0; i < dim; i++){
+ Integer element = Integer.valueOf(i);
+ if (!(redAtoms.contains(element)))
+ {
+ blueAtoms.add(element);
+ }
}
+ }
+ /*** dividing over ***/
+ redChild[0] = dad.getBuilder().newAtomContainer(dad);
+ blueChild[0] = dad.getBuilder().newAtomContainer(dad);
+ redChild[1] = dad.getBuilder().newAtomContainer(mom);
+ blueChild[1] = dad.getBuilder().newAtomContainer(mom);
+
+ List blueAtomsInRedChild0 = new ArrayList();
+ for (int j = 0; j < blueAtoms.size(); j++)
+ {
+ blueAtomsInRedChild0.add(redChild[0].getAtom((Integer)blueAtoms.get(j)));
}
- }
-
-
- for (int j = 0; j < redAtoms.size(); j++)
- {
- Iterator bonds = blueChild[0].bonds().iterator();
- while (bonds.hasNext()) {
- IBond bond = (IBond)bonds.next();
- if (bond.contains(blueChild[0].getAtom(((Integer)redAtoms.get(j)).intValue())))
- {
- bonds.remove();
+ for (int j = 0; j < blueAtomsInRedChild0.size(); j++)
+ {
+ redChild[0].removeAtomAndConnectedElectronContainers(blueAtomsInRedChild0.get(j));
+ }
+ List blueAtomsInRedChild1 = new ArrayList();
+ for (int j = 0; j < blueAtoms.size(); j++)
+ {
+ blueAtomsInRedChild1.add(redChild[1].getAtom((Integer)blueAtoms.get(j)));
+ }
+ for (int j = 0; j < blueAtomsInRedChild1.size(); j++)
+ {
+ redChild[1].removeAtomAndConnectedElectronContainers(blueAtomsInRedChild1.get(j));
+ }
+ List redAtomsInBlueChild0 = new ArrayList();
+ for (int j = 0; j < redAtoms.size(); j++)
+ {
+ redAtomsInBlueChild0.add(blueChild[0].getAtom((Integer)redAtoms.get(j)));
+ }
+ for (int j = 0; j < redAtomsInBlueChild0.size(); j++)
+ {
+ blueChild[0].removeAtomAndConnectedElectronContainers(redAtomsInBlueChild0.get(j));
+ }
+ List redAtomsInBlueChild1 = new ArrayList();
+ for (int j = 0; j < redAtoms.size(); j++)
+ {
+ redAtomsInBlueChild1.add(blueChild[1].getAtom((Integer)redAtoms.get(j)));
+ }
+ for (int j = 0; j < redAtomsInBlueChild1.size(); j++)
+ {
+ blueChild[1].removeAtomAndConnectedElectronContainers(redAtomsInBlueChild1.get(j));
+ }
+ //if the two fragments of one and only one parent have an uneven number
+ //of attachment points, we need to rearrange them
+ SaturationChecker satCheck = new SaturationChecker();
+ double red1attachpoints=0;
+ for(int i=0;i children=new ArrayList(2);
+ for (int f = 0; f < 2; f++)
{
- bonds.remove();
+ try{
+ children.add(f, pfsm.generate(newstrucs[f]).getAtomContainer(0));
+ //System.err.println("F "+writer.createSMILES(new Molecule(children.get(f))) );
+ }catch(Exception ex){
+
+ }
}
+ if(children.size()==2 && ConnectivityChecker.isConnected(children.get(0)) && ConnectivityChecker.isConnected(children.get(1)))
+ return children;
}
- }
-
-
- redChild[0].add(blueChild[1]);
- if (children.size()==2)
- {
- redChild[1].add(blueChild[0]);
- }
-
-
-
- for (int f = 0; f < children.size(); f++)
- {
- pfsm.setAtomContainer(redChild[f]);
- children.add(f, pfsm.generate());
- }
- return children;
+ tries++;
+ if(tries>20)
+ throw new CDKException("Could not mate these properly");
+ }
}
}