1 /* Copyright (C) 2009-2010 Syed Asad Rahman <asad@ebi.ac.uk> 2 * 3 * Contact: cdk-devel@lists.sourceforge.net 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public License 7 * as published by the Free Software Foundation; either version 2.1 8 * of the License, or (at your option) any later version. 9 * All we ask is that proper credit is given for our work, which includes 10 * - but is not limited to - adding the above copyright notice to the beginning 11 * of your source code files, and to any copyright notice that you may distribute 12 * with programs based on this work. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 */ 23 package org.openscience.cdk.smsd.algorithm.vflib; 24 25 import java.io.IOException; 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.HashMap; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.TreeMap; 32 import java.util.logging.Level; 33 import org.openscience.cdk.exception.CDKException; 34 import org.openscience.cdk.interfaces.IAtom; 35 import org.openscience.cdk.interfaces.IAtomContainer; 36 import org.openscience.cdk.isomorphism.matchers.IQueryAtomContainer; 37 import org.openscience.cdk.smsd.algorithm.mcgregor.McGregor; 38 import org.openscience.cdk.smsd.algorithm.vflib.interfaces.IMapper; 39 import org.openscience.cdk.smsd.algorithm.vflib.interfaces.INode; 40 import org.openscience.cdk.smsd.algorithm.vflib.interfaces.IQuery; 41 import org.openscience.cdk.smsd.algorithm.vflib.map.VFMapper; 42 import org.openscience.cdk.smsd.algorithm.vflib.query.QueryCompiler; 43 import org.openscience.cdk.smsd.interfaces.AbstractSubGraph; 44 import org.openscience.cdk.smsd.interfaces.IMCSBase; 45 import org.openscience.cdk.smsd.tools.MolHandler; 46 import org.openscience.cdk.tools.ILoggingTool; 47 import org.openscience.cdk.tools.LoggingToolFactory; 48 49 /** 50 * This is an ultra fast method to report if query 51 * is a substructure for target molecule. If this case is true 52 * then it returns only one mapping. 53 * 54 * This is much faster than {@link 55 * org.openscience.cdk.smsd.algorithm.vflib.VFlibMCSHandler} class 56 * as it only reports first match and backtracks. 57 * 58 * This class should only be used to report if a query 59 * graph is a substructure of the target graph. 60 * 61 * @cdk.module smsd 62 * @cdk.githash 63 * @author Syed Asad Rahman <asad@ebi.ac.uk> 64 * @deprecated SMSD has been deprecated from the CDK with a newer, more recent 65 * version of SMSD is available at <a href="http://github.com/asad/smsd">http://github.com/asad/smsd</a>. 66 */ 67 @Deprecated 68 public class VFlibTurboHandler extends AbstractSubGraph implements IMCSBase { 69 70 private List<Map<IAtom, IAtom>> allAtomMCS = null; 71 private Map<IAtom, IAtom> atomsMCS = null; 72 private List<Map<IAtom, IAtom>> allAtomMCSCopy = null; 73 private Map<Integer, Integer> firstMCS = null; 74 private List<Map<Integer, Integer>> allMCS = null; 75 private List<Map<Integer, Integer>> allMCSCopy = null; 76 private IQueryAtomContainer queryMol = null; 77 private IAtomContainer mol1 = null; 78 private IAtomContainer mol2 = null; 79 private Map<INode, IAtom> vfLibSolutions = null; 80 private int vfMCSSize = -1; 81 private boolean bondMatchFlag = false; 82 private final static ILoggingTool LOGGER = LoggingToolFactory 83 .createLoggingTool(VFlibTurboHandler.class); 84 85 /** 86 * Constructor for an extended VF Algorithm for the MCS search 87 */ VFlibTurboHandler()88 public VFlibTurboHandler() { 89 allAtomMCS = new ArrayList<Map<IAtom, IAtom>>(); 90 allAtomMCSCopy = new ArrayList<Map<IAtom, IAtom>>(); 91 atomsMCS = new HashMap<IAtom, IAtom>(); 92 firstMCS = new TreeMap<Integer, Integer>(); 93 allMCS = new ArrayList<Map<Integer, Integer>>(); 94 allMCSCopy = new ArrayList<Map<Integer, Integer>>(); 95 } 96 setFirstMappings()97 private void setFirstMappings() { 98 if (!allAtomMCS.isEmpty()) { 99 atomsMCS.putAll(allAtomMCS.get(0)); 100 firstMCS.putAll(allMCS.get(0)); 101 } 102 } 103 mcgregorFlag()104 private boolean mcgregorFlag() { 105 int commonAtomCount = checkCommonAtomCount(getReactantMol(), getProductMol()); 106 if (commonAtomCount > vfMCSSize && commonAtomCount > vfMCSSize) { 107 return true; 108 } 109 return false; 110 } 111 112 /** {@inheritDoc} 113 * 114 * Set the VFLib MCS software 115 * 116 * @param reactant 117 * @param product 118 */ 119 @Override set(MolHandler reactant, MolHandler product)120 public void set(MolHandler reactant, MolHandler product) { 121 mol1 = reactant.getMolecule(); 122 mol2 = product.getMolecule(); 123 } 124 125 /** {@inheritDoc} 126 * 127 * @param source 128 * @param target 129 */ 130 @Override set(IQueryAtomContainer source, IAtomContainer target)131 public void set(IQueryAtomContainer source, IAtomContainer target) { 132 queryMol = source; 133 mol2 = target; 134 } 135 hasMap(Map<Integer, Integer> map, List<Map<Integer, Integer>> mapGlobal)136 private boolean hasMap(Map<Integer, Integer> map, List<Map<Integer, Integer>> mapGlobal) { 137 for (Map<Integer, Integer> test : mapGlobal) { 138 if (test.equals(map)) { 139 return true; 140 } 141 } 142 return false; 143 } 144 145 /** {@inheritDoc} 146 * 147 */ 148 @Override getAllAtomMapping()149 public List<Map<IAtom, IAtom>> getAllAtomMapping() { 150 return Collections.unmodifiableList(allAtomMCS); 151 } 152 153 /** {@inheritDoc} 154 */ 155 @Override getAllMapping()156 public List<Map<Integer, Integer>> getAllMapping() { 157 return Collections.unmodifiableList(allMCS); 158 } 159 160 /** {@inheritDoc} 161 */ 162 @Override getFirstAtomMapping()163 public Map<IAtom, IAtom> getFirstAtomMapping() { 164 return Collections.unmodifiableMap(atomsMCS); 165 } 166 167 /** {@inheritDoc} 168 */ 169 @Override getFirstMapping()170 public Map<Integer, Integer> getFirstMapping() { 171 return Collections.unmodifiableMap(firstMCS); 172 } 173 checkCommonAtomCount(IAtomContainer reactantMolecule, IAtomContainer productMolecule)174 private int checkCommonAtomCount(IAtomContainer reactantMolecule, IAtomContainer productMolecule) { 175 ArrayList<String> atoms = new ArrayList<String>(); 176 for (int i = 0; i < reactantMolecule.getAtomCount(); i++) { 177 atoms.add(reactantMolecule.getAtom(i).getSymbol()); 178 } 179 int common = 0; 180 for (int i = 0; i < productMolecule.getAtomCount(); i++) { 181 String symbol = productMolecule.getAtom(i).getSymbol(); 182 if (atoms.contains(symbol)) { 183 atoms.remove(symbol); 184 common++; 185 } 186 } 187 return common; 188 } 189 searchVFMappings()190 private void searchVFMappings() { 191 // System.out.println("searchVFMappings "); 192 IQuery query = null; 193 IMapper mapper = null; 194 vfLibSolutions = new HashMap<INode, IAtom>(); 195 if (queryMol != null) { 196 query = new QueryCompiler(queryMol).compile(); 197 mapper = new VFMapper(query); 198 if (mapper.hasMap(getProductMol())) { 199 Map<INode, IAtom> map = mapper.getFirstMap(getProductMol()); 200 if (map != null) { 201 vfLibSolutions.putAll(map); 202 } 203 } 204 setVFMappings(true, query); 205 } else if (getReactantMol().getAtomCount() <= getProductMol().getAtomCount()) { 206 query = new QueryCompiler(mol1, isBondMatchFlag()).compile(); 207 mapper = new VFMapper(query); 208 if (mapper.hasMap(getProductMol())) { 209 Map<INode, IAtom> map = mapper.getFirstMap(getProductMol()); 210 if (map != null) { 211 vfLibSolutions.putAll(map); 212 } 213 } 214 setVFMappings(true, query); 215 } else { 216 query = new QueryCompiler(getProductMol(), isBondMatchFlag()).compile(); 217 mapper = new VFMapper(query); 218 if (mapper.hasMap(getReactantMol())) { 219 Map<INode, IAtom> map = mapper.getFirstMap(getReactantMol()); 220 if (map != null) { 221 vfLibSolutions.putAll(map); 222 } 223 } 224 setVFMappings(false, query); 225 } 226 } 227 searchMcGregorMapping()228 private void searchMcGregorMapping() throws CDKException, IOException { 229 List<List<Integer>> mappings = new ArrayList<List<Integer>>(); 230 for (Map<Integer, Integer> firstPassMappings : allMCSCopy) { 231 McGregor mgit = new McGregor(getReactantMol(), getProductMol(), mappings, isBondMatchFlag()); 232 mgit.startMcGregorIteration(mgit.getMCSSize(), firstPassMappings); //Start McGregor search 233 mappings = mgit.getMappings(); 234 mgit = null; 235 } 236 // System.out.println("\nSol count after MG" + mappings.size()); 237 setMcGregorMappings(mappings); 238 vfMCSSize = vfMCSSize / 2; 239 // System.out.println("After set Sol count MG" + allMCS.size()); 240 // System.out.println("MCSSize " + vfMCSSize + "\n"); 241 } 242 setVFMappings(boolean ronp, IQuery query)243 private void setVFMappings(boolean ronp, IQuery query) { 244 int counter = 0; 245 246 Map<IAtom, IAtom> atomatomMapping = new HashMap<IAtom, IAtom>(); 247 Map<Integer, Integer> indexindexMapping = new TreeMap<Integer, Integer>(); 248 if (vfLibSolutions.size() > vfMCSSize) { 249 this.vfMCSSize = vfLibSolutions.size(); 250 allAtomMCSCopy.clear(); 251 allMCSCopy.clear(); 252 counter = 0; 253 } 254 for (Map.Entry<INode, IAtom> mapping : vfLibSolutions.entrySet()) { 255 IAtom qAtom = null; 256 IAtom tAtom = null; 257 if (ronp) { 258 qAtom = query.getAtom(mapping.getKey()); 259 tAtom = mapping.getValue(); 260 } else { 261 tAtom = query.getAtom(mapping.getKey()); 262 qAtom = mapping.getValue(); 263 } 264 Integer qIndex = Integer.valueOf(getReactantMol().indexOf(qAtom)); 265 Integer tIndex = Integer.valueOf(getProductMol().indexOf(tAtom)); 266 if (qIndex != null && tIndex != null) { 267 atomatomMapping.put(qAtom, tAtom); 268 indexindexMapping.put(qIndex, tIndex); 269 } else { 270 try { 271 throw new CDKException("Atom index pointing to NULL"); 272 } catch (CDKException ex) { 273 LOGGER.error(Level.SEVERE, null, ex); 274 } 275 } 276 } 277 // System.out.println("indexindexMapping " + indexindexMapping.size()); 278 // System.out.println("MCS Size " + vfMCSSize); 279 if (!atomatomMapping.isEmpty() && !hasMap(indexindexMapping, allMCSCopy) 280 && indexindexMapping.size() == vfMCSSize) { 281 allAtomMCSCopy.add(counter, atomatomMapping); 282 allMCSCopy.add(counter, indexindexMapping); 283 counter++; 284 } 285 // System.out.println("allMCSCopy " + allMCSCopy.size()); 286 } 287 setMcGregorMappings(List<List<Integer>> mappings)288 private void setMcGregorMappings(List<List<Integer>> mappings) throws CDKException { 289 int counter = 0; 290 this.vfMCSSize = 0; 291 for (List<Integer> mapping : mappings) { 292 if (mapping.size() > vfMCSSize) { 293 vfMCSSize = (mapping.size() / 2); 294 allAtomMCS.clear(); 295 allMCS.clear(); 296 counter = 0; 297 } 298 Map<IAtom, IAtom> atomatomMapping = new HashMap<IAtom, IAtom>(); 299 Map<Integer, Integer> indexindexMapping = new TreeMap<Integer, Integer>(); 300 for (int index = 0; index < mapping.size(); index += 2) { 301 IAtom qAtom = null; 302 IAtom tAtom = null; 303 304 qAtom = getReactantMol().getAtom(mapping.get(index)); 305 tAtom = getProductMol().getAtom(mapping.get(index + 1)); 306 307 Integer qIndex = mapping.get(index); 308 Integer tIndex = mapping.get(index + 1); 309 310 if (qIndex != -1 && tIndex != -1) { 311 atomatomMapping.put(qAtom, tAtom); 312 indexindexMapping.put(qIndex, tIndex); 313 } else { 314 throw new CDKException("Atom index pointing to NULL"); 315 } 316 } 317 if (!atomatomMapping.isEmpty() && !hasMap(indexindexMapping, allMCS) 318 && (indexindexMapping.size()) == vfMCSSize) { 319 allAtomMCS.add(counter, atomatomMapping); 320 allMCS.add(counter, indexindexMapping); 321 counter++; 322 } 323 } 324 } 325 326 @Override isSubgraph(boolean shouldMatchBonds)327 public boolean isSubgraph(boolean shouldMatchBonds) { 328 setBondMatchFlag(shouldMatchBonds); 329 searchVFMappings(); 330 // boolean flag = mcgregorFlag(); 331 // if (flag && !vfLibSolutions.isEmpty()) { 332 // try { 333 // searchMcGregorMapping(); 334 // } catch (CDKException ex) { 335 // LOGGER.error(Level.SEVERE, null, ex); 336 // } catch (IOException ex) { 337 // LOGGER.error(Level.SEVERE, null, ex); 338 // } 339 // 340 // } else 341 342 if (!allAtomMCSCopy.isEmpty()) { 343 allAtomMCS.addAll(allAtomMCSCopy); 344 allMCS.addAll(allMCSCopy); 345 } 346 setFirstMappings(); 347 return (!allMCS.isEmpty() && allMCS.iterator().next().size() == getReactantMol().getAtomCount()) ? true : false; 348 } 349 350 /** 351 * @return the shouldMatchBonds 352 */ isBondMatchFlag()353 public boolean isBondMatchFlag() { 354 return bondMatchFlag; 355 } 356 357 /** 358 * @param shouldMatchBonds the shouldMatchBonds to set 359 */ setBondMatchFlag(boolean shouldMatchBonds)360 public void setBondMatchFlag(boolean shouldMatchBonds) { 361 this.bondMatchFlag = shouldMatchBonds; 362 } 363 getReactantMol()364 private IAtomContainer getReactantMol() { 365 return queryMol == null ? mol1 : queryMol; 366 } 367 getProductMol()368 private IAtomContainer getProductMol() { 369 return mol2; 370 } 371 } 372