com.actelion.research.chem.Mutator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
/*
* Copyright 2017 Idorsia Pharmaceuticals Ltd., Hegenheimermattweg 91, CH-4123 Allschwil, Switzerland
*
* This file is part of DataWarrior.
*
* DataWarrior is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* DataWarrior 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 General Public License for more details.
* You should have received a copy of the GNU General Public License along with DataWarrior.
* If not, see http://www.gnu.org/licenses/.
*
* @author Thomas Sander
*/
package com.actelion.research.chem;
import com.actelion.research.chem.coords.CoordinateInventor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
public class Mutator {
public static final int MUTATION_GROW = Mutation.MUTATION_ADD_ATOM
| Mutation.MUTATION_INSERT_ATOM;
public static final int MUTATION_SHRINK = Mutation.MUTATION_CUTOUT_ATOM
| Mutation.MUTATION_DELETE_ATOM
| Mutation.MUTATION_DELETE_SUBSTITUENT
| Mutation.MUTATION_CUTOUT_SFRAGMENT;
public static final int MUTATION_KEEP_SIZE = Mutation.MUTATION_CHANGE_ATOM
| Mutation.MUTATION_CLOSE_RING
| Mutation.MUTATION_CHANGE_BOND
| Mutation.MUTATION_DELETE_BOND
| Mutation.MUTATION_CHANGE_RING
| Mutation.MUTATION_CLOSE_RING_AND_AROMATIZE
| Mutation.MUTATION_TOGGLE_AMID_SULFONAMID
| Mutation.MUTATION_MIGRATE
| Mutation.MUTATION_SWAP_SUBSTITUENT
| Mutation.MUTATION_INVERT_PARITY;
public static final int MUTATION_ANY = MUTATION_GROW
| MUTATION_SHRINK
| MUTATION_KEEP_SIZE;
private static final int cMinRingClosureSize = 3;
private static final int cMaxRingClosureSize = 7;
private static final int cDefaultMinAtoms = 4;
private static final int cDefaultOptAtoms = 9;
private static final int cDefaultMaxAtoms = 24;
private static final double cProbabilityFactor = 1.0f; // larger/smaller values than 1.0 over/under-express natural probabilities
// Increase back&forth probabilities to better represent natural equilibriums where mutation path to one of two states is unlikely
private static final double BOOST_CHANGE_RING = 1.0;
private static final double BOOST_TOGGLE_AMID_SULFONAMID = 10.f;
private static final double BOOST_CLOSE_RING = 1.0f;
private static final double cMinEductProbability = 0.00001f;
private Random mRandom;
private StereoMolecule mMolCopy = new StereoMolecule();
private StereoMolecule mMol = new StereoMolecule();
private AtomTypeList mAtomTypeList;
private Canonizer mCanonizer;
private boolean[] mIsPrimaryAtom;
private int mMinAtoms,mOptAtoms,mMaxAtoms;
private double mGrowBoost;
private MutationBiasProvider mBiasProvider;
/**
* Creates a new Mutator that calculates probabilities of individual mutations from
* a given atom type file. For every potential mutation the algorithm calculates
* a probability considering the frequencies of broken and formed atom types during the conversion.
* If no type list is given, all possible mutations are considered equally likely.
* New type files can be created from an sdf or dwar file like this:
* new AtomTypeList("/somepath/chembl14.dwar", AtomTypeCalculator.cPropertiesForMutator).writeTypeFile("/somepath/chembl14.typ");
* This would cause a file /somepath/chembl14.typ to be created with the statistics taken from chembl14.dwar.
* @param filename null or name of a atomTypeList file ('*.typ')
*/
public Mutator(String filename) {
if (filename != null) {
try {
mAtomTypeList = new AtomTypeList(filename, AtomTypeCalculator.cPropertiesForMutator);
mAtomTypeList.calculateProbabilities();
}
catch (Exception e) {
e.printStackTrace();
}
}
mRandom = new Random();
mGrowBoost = 1.0;
mMinAtoms = cDefaultMinAtoms;
mOptAtoms = cDefaultOptAtoms;
mMaxAtoms = cDefaultMaxAtoms;
}
/**
* Creates a new Mutator that calculates probabilities of individual mutations from
* a given atom type list. For every potential mutation the algorithm calculates
* a probability considering the frequencies of broken and formed atom types during the conversion.
* If no type list is given, all possible mutations are considered equally likely.
* New type files can be created from an sdf or dwar file like this:
* new AtomTypeList().create("/somepath/chembl14.dwar", AtomTypeCalculator.cPropertiesForMutator);
* This would cause a file /somepath/chembl14.typ to be created with the statistics taken from chembl14.dwar.
* Instantiating multiple Mutator objects from the same AtomTypeList is thread-safe.
* @param atomTypeList null or name of a atomTypeList file ('*.typ')
*/
public Mutator(AtomTypeList atomTypeList) {
mAtomTypeList = atomTypeList;
mAtomTypeList.calculateProbabilities();
mRandom = new Random();
mGrowBoost = 1.0;
mMinAtoms = cDefaultMinAtoms;
mOptAtoms = cDefaultOptAtoms;
mMaxAtoms = cDefaultMaxAtoms;
}
public void setBiasProvider(MutationBiasProvider mbp) {
mBiasProvider = mbp;
}
public void setGrowBoost(double boost) {
mGrowBoost = boost;
}
public void setPreferredSize(int minAtoms, int preferredAtoms, int maxAtoms) {
mMinAtoms = minAtoms;
mOptAtoms = preferredAtoms;
mMaxAtoms = maxAtoms;
}
public StereoMolecule[] getMutatedSet(StereoMolecule mol,
int mutationType,
boolean regulateSize,
int count) {
ArrayList mutationList = generateMutationList(mol, mutationType, regulateSize);
if (count > mutationList.size())
count = mutationList.size();
StereoMolecule[] set = new StereoMolecule[count];
for (int i=0; i mutate(StereoMolecule mol) {
return mutate(mol, MUTATION_ANY, true);
}
/**
* Does an in-place mutation of the molecule allowing the defined mutation kinds at any of the molecules unselected atoms.
* @param mol
* @param mutationType MUTATION_ANY, MUTATION_GROW, MUTATION_KEEP_SIZE, or MUTATION_SHRINK or other combination of allowed mutations types
* @param regulateSize whether to regulate the molecule size within 4 to 24 non-H atoms or what was defined by setPreferredSize()
* @return list of all not-used mutations or null if no mutation was done because no possible mutation was found
*/
public ArrayList mutate(StereoMolecule mol,
int mutationType,
boolean regulateSize) {
ArrayList ml = generateMutationList(mol, mutationType, regulateSize);
if (ml.size() == 0) {
System.out.println("no possible mutation found. ID-Code:"+new Canonizer(mol, Canonizer.ENCODE_ATOM_SELECTION).getIDCode());
return null;
}
mutate(mol, ml);
return ml;
}
/**
* Selects a likely mutation from the list, performs the mutation and removes it from the list.
* If the mutation list is empty, then no mutation is performed.
* @param mol
* @param mutationList
*/
public void mutate(StereoMolecule mol, ArrayList mutationList) {
if (!mutationList.isEmpty()) {
Mutation mutation = selectLikelyMutation(mutationList);
if (mutation != null) {
performMutation(mol, mutation);
}
}
}
/**
* Creates a list of possible mutations and their probabilities
* @param mol
* @param mutationType MUTATION_ANY, MUTATION_GROW, MUTATION_KEEP_SIZE, or MUTATION_SHRINK or other combination of allowed mutations types
* @param regulateSize if true keeps non-H atoms between 4 and 24 with an optimum at 9 or what was defined by setPreferredSize().
*/
public ArrayList generateMutationList(StereoMolecule mol,
int mutationType,
boolean regulateSize) {
mMol = mol;
if (mBiasProvider != null)
mBiasProvider.setBiasReference(mol);
detectSymmetry();
ArrayList mutationList = new ArrayList();
ArrayList substituentList = createSubstituentList();
if (!regulateSize
|| (mRandom.nextDouble() > (float)(mMol.getAtoms() - mOptAtoms)
/ (float)(mMaxAtoms - mOptAtoms))) {
if ((mutationType & Mutation.MUTATION_ADD_ATOM) != 0)
addProbabilitiesForAddAtom(mutationList);
if ((mutationType & Mutation.MUTATION_INSERT_ATOM) != 0)
addProbabilitiesForInsertAtom(mutationList);
}
if ((mutationType & Mutation.MUTATION_CHANGE_ATOM) != 0)
addProbabilitiesForChangeAtom(mutationList);
if (!regulateSize
|| (mRandom.nextDouble() < (float)(mMol.getAtoms() - mMinAtoms)
/ (float)(mOptAtoms - mMinAtoms))) {
if ((mutationType & Mutation.MUTATION_DELETE_ATOM) != 0)
addProbabilitiesForDeleteAtom(mutationList);
if ((mutationType & Mutation.MUTATION_CUTOUT_ATOM) != 0)
addProbabilitiesForCutOutAtom(mutationList);
if ((mutationType & Mutation.MUTATION_DELETE_SUBSTITUENT) != 0)
addProbabilitiesForDeleteSubstituent(mutationList, substituentList);
if ((mutationType & Mutation.MUTATION_CUTOUT_SFRAGMENT) != 0)
addProbabilitiesForCutOutFragment(mutationList);
}
if ((mutationType & (Mutation.MUTATION_CLOSE_RING | Mutation.MUTATION_CLOSE_RING_AND_AROMATIZE)) != 0)
addProbabilitiesForCloseRing(mutationList, mutationType);
if ((mutationType & (Mutation.MUTATION_TOGGLE_AMID_SULFONAMID)) != 0)
addProbabilitiesForToggleAmidSulfonamid(mutationList);
if ((mutationType & Mutation.MUTATION_CHANGE_BOND) != 0)
addProbabilitiesForChangeBond(mutationList);
if ((mutationType & Mutation.MUTATION_DELETE_BOND) != 0)
addProbabilitiesForDeleteBond(mutationList);
if ((mutationType & Mutation.MUTATION_CHANGE_RING) != 0)
addProbabilitiesForChangeRing(mutationList);
if ((mutationType & Mutation.MUTATION_MIGRATE) != 0)
addProbabilitiesForMigrate(mutationList);
if ((mutationType & Mutation.MUTATION_SWAP_SUBSTITUENT) != 0)
addProbabilitiesForSwapSubstituent(mutationList, substituentList);
if ((mutationType & Mutation.MUTATION_INVERT_PARITY) != 0)
addProbabilitiesForInvertParity(mutationList);
if (cProbabilityFactor != 1)
tweakProbabilities(mutationList);
return mutationList;
}
private void tweakProbabilities(ArrayList mutationList) {
for (Mutation mutation:mutationList)
mutation.mProbability = Math.pow(mutation.mProbability, cProbabilityFactor);
}
private void detectSymmetry() {
mCanonizer = new Canonizer(mMol, Canonizer.CREATE_SYMMETRY_RANK);
mIsPrimaryAtom = new boolean[mMol.getAtoms()];
// here we count unselected atoms per rank
int[] rankCount = new int[1+mMol.getAtoms()];
for (int atom=0; atom mutationList){
for (int atom=0; atom 3) ? 3 : freeValence;
if( maxBondOrder > 0) {
mMol.copyMolecule(mMolCopy);
int newAtom = mMolCopy.addAtom(6);
int newBond = mMolCopy.addBond(atom, newAtom, Molecule.cBondTypeSingle);
//loop for single float or triple bond to add
for (int bondOrder=1; bondOrder<=maxBondOrder; bondOrder++) {
//check if the atom to add has enough bonds
boolean allowed = false;
for (int i=0; i 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_ADD_ATOM, atom, -1, atomicNo, bondType, p));
}
}
}
}
}
}
}
private void addProbabilitiesForInsertAtom(ArrayList mutationList) {
for (int bond=0; bond 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_INSERT_ATOM, bond, -1, atomicNo, -1, p));
}
}
}
}
}
}
}
private void addProbabilitiesForChangeAtom(ArrayList mutationList) {
for (int atom=0; atom 1
&& (proposedAtomicNo == 9
|| proposedAtomicNo == 17
|| proposedAtomicNo == 35
|| proposedAtomicNo == 53))
continue;
if (valences > 2
&& proposedAtomicNo == 8)
continue;
if (valences > 3
&& proposedAtomicNo == 5)
continue;
if (valences > 4
&& (proposedAtomicNo == 6
|| proposedAtomicNo == 7))
continue;
if (valences > 5
&& proposedAtomicNo == 15)
continue;
mMol.copyMolecule(mMolCopy);
mMolCopy.setAtomicNo(atom, proposedAtomicNo);
mMolCopy.ensureHelperArrays(Molecule.cHelperRings);
double f_Educt = Math.max(cMinEductProbability, getFrequency(mMol,atom));
double f_Product = getFrequency(mMolCopy,atom);
for (int j=0; j 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_CHANGE_ATOM, atom, -1, proposedAtomicNo, -1, p));
}
}
}
}
}
private void addProbabilitiesForDeleteAtom(ArrayList mutationList) {
for (int atom=0; atom 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_DELETE_ATOM, atom, -1, -1, -1, p));
}
}
}
}
}
}
private void addProbabilitiesForCutOutAtom(ArrayList mutationList) {
for (int atom=0; atom 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_CUTOUT_ATOM, atom, -1, -1, -1, p));
}
}
}
}//end_deleting
private void addProbabilitiesForToggleAmidSulfonamid(ArrayList mutationList) {
int[] oxygen = new int[4];
for (int atom=0; atom 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_TOGGLE_AMID_SULFONAMID, atom, oxygen[1], -1, -1, p));
}
}
}
}
}
private void addProbabilitiesForCloseRing(ArrayList mutationList, int mode) {
for (int atom1=0; atom1= cMaxRingClosureSize)
break;
for (int i=0; i 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_CLOSE_RING_AND_AROMATIZE, atom1, atom2, ringSize, ringAtom, p));
}
}
}
}
}
if ((mode & Mutation.MUTATION_CLOSE_RING) != 0 && order == 1) {
mMol.copyMolecule(mMolCopy);
mMolCopy.addBond(atom1, atom2, getBondTypeFromOrder(order));
double f_Educt1 = Math.max(cMinEductProbability, getFrequency(mMol, atom1));
double f_Educt2 = Math.max(cMinEductProbability, getFrequency(mMol, atom2));
double f_Product1 = getFrequency(mMolCopy, atom1);
double f_Product2 = getFrequency(mMolCopy, atom2);
double p = (mAtomTypeList == null) ? 1.0f : mAtomTypeList.getRingSizeAdjust(graphLevel[atom2]);
p *= BOOST_CLOSE_RING * Math.sqrt(f_Product1 * f_Product2 / (f_Educt1 * f_Educt2));
if (p > 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_CLOSE_RING, atom1, atom2, getBondTypeFromOrder(order), -1, p));
}
}
}
}
}
}
}
private void addProbabilitiesForChangeBond(ArrayList mutationList) {
for (int bond=0; bond mMol.getFreeValence(atom2))
minFreeValence = mMol.getFreeValence(atom2);
int maxBondOrder = mMol.getBondOrder(bond) + minFreeValence;
if (maxBondOrder > 3)
maxBondOrder = 3;
if (mMol.isAromaticBond(bond)) {
if (mMol.getBondOrder(bond) == 1)
continue;
maxBondOrder = 2;
}
if (mMol.isSmallRingBond(bond)) {
if (mMol.getBondOrder(bond) == 1
&& mMol.getAtomPi(atom1)+mMol.getAtomPi(atom2) != 0)
maxBondOrder = 1;
else if (maxBondOrder > 2)
maxBondOrder = 2;
}
if (maxBondOrder == 2
&& (mMol.getAtomicNo(atom1) < 5
|| (mMol.getAtomicNo(atom1) > 8
&& mMol.getAtomicNo(atom1) != 15
&& mMol.getAtomicNo(atom1) != 16)
|| mMol.getAtomicNo(atom2) < 5
|| (mMol.getAtomicNo(atom2) > 8
&& mMol.getAtomicNo(atom2) != 15
&& mMol.getAtomicNo(atom2) != 16)))
maxBondOrder = 1;
for (int bondOrder=1; bondOrder<=maxBondOrder; bondOrder++) {
if (bondOrder == mMol.getBondOrder(bond))
continue;
mMol.copyMolecule(mMolCopy);
mMolCopy.setBondType(bond, getBondTypeFromOrder(bondOrder));
double f_Educt1 = Math.max(cMinEductProbability, getFrequency(mMol, atom1));
double f_Educt2 = Math.max(cMinEductProbability, getFrequency(mMol, atom2));
double f_Product1 = getFrequency(mMolCopy, atom1);
double f_Product2 = getFrequency(mMolCopy, atom2);
double p = Math.sqrt(f_Product1 * f_Product2 / (f_Educt1 * f_Educt2));
if (p > 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_CHANGE_BOND, bond, -1, getBondTypeFromOrder(bondOrder), -1, p));
}
}
}
}
}
}
}
private void addProbabilitiesForDeleteBond(ArrayList mutationList) {
for (int bond=0; bond 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_DELETE_BOND, bond, -1, -1, -1, p));
}
}
}
}
}
}
}
private void addProbabilitiesForChangeRing(ArrayList mutationList) {
mMol.ensureHelperArrays(Molecule.cHelperRings);
RingCollection ringSet = mMol.getRingSet();
for (int ring=0; ring 0
&& (ringSize == 6
|| ringSet.isAromatic(ring)))
break;
if (ringSize == 5
&& mMol.getAtomicNo(ringAtom[heteroPosition]) != 7
&& mMol.getAtomicNo(ringAtom[heteroPosition]) != 8
&& mMol.getAtomicNo(ringAtom[heteroPosition]) != 16)
continue;
mMol.copyMolecule(mMolCopy);
mMolCopy.ensureHelperArrays(Molecule.cHelperRings);
if (!changeAromaticity(mMolCopy, ring, heteroPosition))
continue;
double f_Educt = 1.0;
double f_Product = 1.0;
for (int atom=0; atom 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_CHANGE_RING, ring, -1, heteroPosition, -1, p));
}
}
}
}
}
}
private void addProbabilitiesForMigrate(ArrayList mutationList) {
for (int atom=0; atom 2) {
for (int i=0; i 0) {
mMol.copyMolecule(mMolCopy);
for (int k=0; k<2; k++)
if (mMolCopy.getBondAtom(k, migratingBond) == atom)
mMolCopy.setBondAtom(k, migratingBond, destinationAtom);
double f_Educt = Math.max(cMinEductProbability, getFrequency(mMol, atom))
* Math.max(cMinEductProbability, getFrequency(mMol, migratingAtom))
* Math.max(cMinEductProbability, getFrequency(mMol, destinationAtom));
double f_Product = getFrequency(mMolCopy, atom)
* getFrequency(mMolCopy, migratingAtom)
* getFrequency(mMolCopy, destinationAtom);
double p = Math.sqrt(f_Product / f_Educt); // slight boost
if (p > 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_MIGRATE, migratingBond, -1, atom, destinationAtom, p));
}
}
}
}
}
}
}
}
}
private void addProbabilitiesForSwapSubstituent(ArrayList mutationList,
ArrayList substituentList) {
for (MutatorSubstituent s1:substituentList) {
if (mIsPrimaryAtom[s1.firstAtom]) {
for (MutatorSubstituent s2:substituentList) {
if (mIsPrimaryAtom[s2.firstAtom]
&& s1.coreAtom != s2.coreAtom
&& s1.bond != s2.bond) {
mMol.copyMolecule(mMolCopy);
for (int k=0; k<2; k++) {
if (mMolCopy.getBondAtom(k, s1.bond) == s1.firstAtom)
mMolCopy.setBondAtom(k, s1.bond, s2.firstAtom);
if (mMolCopy.getBondAtom(k, s2.bond) == s2.firstAtom)
mMolCopy.setBondAtom(k, s2.bond, s1.firstAtom);
}
double f_Educt = Math.max(cMinEductProbability, getFrequency(mMol, s1.coreAtom))
* Math.max(cMinEductProbability, getFrequency(mMol, s1.firstAtom))
* Math.max(cMinEductProbability, getFrequency(mMol, s2.coreAtom))
* Math.max(cMinEductProbability, getFrequency(mMol, s2.firstAtom));
double f_Product = getFrequency(mMolCopy, s1.coreAtom)
* getFrequency(mMolCopy, s1.firstAtom)
* getFrequency(mMolCopy, s2.coreAtom)
* getFrequency(mMolCopy, s2.firstAtom);
double p = Math.sqrt(f_Product / f_Educt); // slight boost
if (p > 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_SWAP_SUBSTITUENT, s1.coreAtom, s2.coreAtom, s1.firstAtom, s2.firstAtom, p));
}
}
}
}
}
}
private void addProbabilitiesForDeleteSubstituent(ArrayList mutationList,
ArrayList substituentList) {
for (MutatorSubstituent s:substituentList) {
if (mIsPrimaryAtom[s.coreAtom]) {
boolean[] isMemberAtom = new boolean[mMol.getAllAtoms()];
mMol.getSubstituent(s.coreAtom, s.firstAtom, isMemberAtom, null, null);
boolean selectedAtomFound = false;
for (int atom=0; atom 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_DELETE_SUBSTITUENT, s.coreAtom, -1, s.firstAtom, -1, p));
}
}
}
}
}
private void addProbabilitiesForCutOutFragment(ArrayList mutationList) {
for (int atom=0; atom 2) {
int ringBondCount = 0;
for (int i=0; i 0.0 && isValidStructure(mMolCopy)) {
if (mBiasProvider != null)
p *= mBiasProvider.getBiasFactor(mMolCopy);
mutationList.add(new Mutation(Mutation.MUTATION_CUTOUT_SFRAGMENT, atom, -1, atom1, atom2, p));
}
}
}
}
}
}
}
}
}
private void addProbabilitiesForInvertParity(ArrayList mutationList) {
for (int atom=0; atom createSubstituentList() {
ArrayList substituentList = new ArrayList();
boolean[] isCentralAtom = ScaffoldHelper.findMurckoScaffold(mMol);
if (isCentralAtom != null) {
for (int bond=0; bond mutationList) {
double probabilitySum = 0.0f;
for (Mutation m:mutationList)
probabilitySum += m.mProbability;
double selector = mRandom.nextDouble() * probabilitySum;
probabilitySum = 0.0f;
for (Mutation m:mutationList) {
probabilitySum += m.mProbability;
if (selector < probabilitySum) {
mutationList.remove(m);
return m;
}
}
return null;
}
/**
* Performs the given mutation on the molecule, updates atom coordinates,
* and updates stereo bonds to reflect lost or new stereo centers.
* @param mol
* @param mutation
*/
public void performMutation(StereoMolecule mol, Mutation mutation) {
mol.ensureHelperArrays(Molecule.cHelperParities);
switch (mutation.mMutationType) {
case Mutation.MUTATION_ADD_ATOM:
int newAtom = mol.addAtom(mutation.mSpecifier1);
mol.addBond(mutation.mWhere1, newAtom, mutation.mSpecifier2);
break;
case Mutation.MUTATION_INSERT_ATOM:
int atom1 = mol.getBondAtom(0, mutation.mWhere1);
int atom2 = mol.getBondAtom(1, mutation.mWhere1);
mol.deleteBond(mutation.mWhere1);
newAtom = mol.addAtom(mutation.mSpecifier1);
mol.addBond(atom1, newAtom, Molecule.cBondTypeSingle);
mol.addBond(atom2, newAtom, Molecule.cBondTypeSingle);
break;
case Mutation.MUTATION_CHANGE_ATOM:
mol.setAtomicNo(mutation.mWhere1, mutation.mSpecifier1);
break;
case Mutation.MUTATION_DELETE_ATOM:
mol.deleteAtom(mutation.mWhere1);
break;
case Mutation.MUTATION_CUTOUT_ATOM:
atom1 = mol.getConnAtom(mutation.mWhere1, 0);
atom2 = mol.getConnAtom(mutation.mWhere1, 1);
mol.addBond(atom1, atom2, Molecule.cBondTypeSingle);
mol.deleteAtom(mutation.mWhere1);
break;
case Mutation.MUTATION_CLOSE_RING:
mol.addBond(mutation.mWhere1, mutation.mWhere2, mutation.mSpecifier1);
break;
case Mutation.MUTATION_CLOSE_RING_AND_AROMATIZE:
mol.addBond(mutation.mWhere1, mutation.mWhere2, mutation.mSpecifier1);
aromatizeRing(mol, mutation.mAtomList, mutation.mSpecifier1);
break;
case Mutation.MUTATION_TOGGLE_AMID_SULFONAMID:
if (mol.getAtomicNo(mutation.mWhere1) == 6) {
mol.setAtomicNo(mutation.mWhere1, 16);
mol.addBond(mutation.mWhere1, mol.addAtom(8), Molecule.cBondTypeDouble);
}
else {
mol.setAtomicNo(mutation.mWhere1, 6);
mol.deleteAtom(mutation.mWhere2);
}
break;
case Mutation.MUTATION_CHANGE_BOND:
mol.setBondType(mutation.mWhere1, mutation.mSpecifier1);
break;
case Mutation.MUTATION_DELETE_BOND:
mol.deleteBond(mutation.mWhere1);
break;
case Mutation.MUTATION_CHANGE_RING:
changeAromaticity(mol, mutation.mWhere1, mutation.mSpecifier1);
break;
case Mutation.MUTATION_MIGRATE:
for (int i=0; i<2; i++)
if (mol.getBondAtom(i, mutation.mWhere1) == mutation.mSpecifier1)
mol.setBondAtom(i, mutation.mWhere1, mutation.mSpecifier2);
break;
case Mutation.MUTATION_DELETE_SUBSTITUENT:
boolean[] atomMask = new boolean[mol.getAtoms()];
mol.getSubstituent(mutation.mWhere1, mutation.mSpecifier1, atomMask, null, null);
mol.deleteAtoms(atomMask);
break;
case Mutation.MUTATION_CUTOUT_SFRAGMENT:
int rootAtom = mutation.mWhere1;
atom1 = mutation.mSpecifier1;
atom2 = mutation.mSpecifier2;
int bond1 = -1;
int bond2 = -1;
for (int i=0; i 0
&& ((mMol.isAromaticAtom(firstMaxConsecutiveRingAtom)
|| mMol.isAromaticAtom(lastMaxConsecutiveRingAtom))
|| (mMol.getAtomPi(firstMaxConsecutiveRingAtom) > 0
&& mMol.getAtomPi(lastMaxConsecutiveRingAtom) > 0)))
penalty++;
if (ringSize - penalty < 3)
return false;
return true;
}
/**
* Runs a rule based check for bicyclic systems with unacceptable strain.
* Checks any bridge between two different atoms of one ring
* connected to different atoms of one ring.
* @param mol
* @return
*/
private boolean isValidStructure(StereoMolecule mol) {
// The largest bridge length (bonds) between two direct ring neighbours
// that would still cause an unacceptable ring strain.
// (this is the smallest allowed chain (bond count) from ring atom to ring atom minus 3!!!)
// First index is ring size, 2nd index is number of bonds between attachment points
// We distinguish 3 types of rings:
// - aromatic or both attachment points sp2
// - one attachment point sp2
// - both attachment points sp3
final int[][] MAX_FORBIDDEN_BRIDGE_LENGTH_AROM = { null, null, null,
{ -1, 2 },
{ -1, 2, 6 },
{ -1, 1, 5 },
{ -1, 1, 4, 6 },
{ -1, 1, 4, 6 } };
final int[][] MAX_FORBIDDEN_BRIDGE_LENGTH_PI = { null, null, null,
{ -1, 1 },
{ -1, 1, 5 },
{ -1, 1, 4 },
{ -1, 0, 3, 4 },
{ -1, 0, 2, 3 } };
final int[][] MAX_FORBIDDEN_BRIDGE_LENGTH_ALIPH = { null, null, null,
{ -1, 0 },
{ -1, -1, 3 },
{ -1, -1, 0 },
{ -1, -1, 0, -1 },
{ -1, -1, 0, -1 } };
mol.ensureHelperArrays(Molecule.cHelperRings);
RingCollection ringSet = mol.getRingSet();
boolean[] neglectAtom = new boolean[mol.getAtoms()];
for (int ring=0; ring 2) {
for (int ci=0; ci 2) {
for (int cj=0; cj 1))
return true;
}
}
return false;
}
private boolean changeAromaticity(StereoMolecule mol, int ring, int heteroPosition) {
mol.ensureHelperArrays(Molecule.cHelperRings);
RingCollection ringSet = mol.getRingSet();
int ringSize = ringSet.getRingSize(ring);
int ringAtom[] = ringSet.getRingAtoms(ring);
int ringBond[] = ringSet.getRingBonds(ring);
if (ringSet.isAromatic(ring)) {
for (int i=0; i 4)
doubleBondPosition1 -= 5;
if (doubleBondPosition2 > 4)
doubleBondPosition2 -= 5;
mol.setBondType(doubleBondPosition1, Molecule.cBondTypeDouble);
mol.setBondType(doubleBondPosition2, Molecule.cBondTypeDouble);
return true;
}
if (ringSize == 6) {
for (int i=0; i= ringSize)
doubleBondIndex -= ringSize;
mol.setBondType(ringBond[doubleBondIndex], Molecule.cBondTypeDouble);
doubleBondIndex += 2;
}
return true;
}
public void printMutationList(ArrayList mutationList, boolean sortByPriority) {
Mutation[] mutation = mutationList.toArray(new Mutation[0]);
if (sortByPriority)
Arrays.sort(mutation, new Comparator() {
@Override public int compare(Mutation m1, Mutation m2) {
return m1.mProbability > m2.mProbability ? -1 : m1.mProbability < m2.mProbability ? 1 : 0;
}
} );
System.out.println("Mutation list ("+mutationList.size()+" mutations):");
for (Mutation m:mutation)
System.out.println(m.toString());
}
class MutatorSubstituent {
public int coreAtom;
public int firstAtom;
public int bond;
public int[] atoms;
// public int size;
public MutatorSubstituent(int coreAtom, int firstAtom, int bond) {
this.coreAtom = coreAtom;
this.firstAtom = firstAtom;
this.bond = bond;
boolean[] isMember = new boolean[mMol.getAllAtoms()];
int count = mMol.getSubstituent(coreAtom, firstAtom, isMember, null, null);
atoms = new int[count];
for (int atom=0, i=0; atom
© 2015 - 2025 Weber Informatics LLC | Privacy Policy