Beispiel #1
0
Subgraphs::DiscrimTuple FragCatalogEntry::getDiscrims() const {
  Subgraphs::DiscrimTuple res;
  if (this->hasProp(common_properties::Discrims)) {
    this->getProp(common_properties::Discrims, res);
  } else {
    PATH_TYPE path;
    for (unsigned int i = 0; i < dp_mol->getNumBonds(); ++i) path.push_back(i);

    // create invariant additions to reflect the functional groups attached to
    // the atoms
    std::vector<std::uint32_t> funcGpInvars;
    gboost::hash<INT_VECT> vectHasher;
    for (ROMol::AtomIterator atomIt = dp_mol->beginAtoms();
         atomIt != dp_mol->endAtoms(); ++atomIt) {
      unsigned int aid = (*atomIt)->getIdx();
      std::uint32_t invar = 0;
      auto mapPos = d_aToFmap.find(aid);
      if (mapPos != d_aToFmap.end()) {
        INT_VECT fGroups = mapPos->second;
        std::sort(fGroups.begin(), fGroups.end());
        invar = vectHasher(fGroups);
      }
      funcGpInvars.push_back(invar);
    }
    res = Subgraphs::calcPathDiscriminators(*dp_mol, path, true, &funcGpInvars);
    this->setProp(common_properties::Discrims, res);
  }

  // std::cout << "DISCRIMS: " << d_descrip  << " ";
  // std::cout << res.get<0>() << " " << res.get<1>() << " " << res.get<2>();
  // std::cout << std::endl;
  return res;
}
Beispiel #2
0
FragCatalogEntry::FragCatalogEntry(const ROMol *omol, const PATH_TYPE &path,
                                   const MatchVectType &aidToFid) {
  PRECONDITION(omol, "bad mol");
  // start with the assumption that this entry is not participating in
  //  any find of fingerprinting
  d_aToFmap.clear();
  setBitId(-1);
  INT_MAP_INT aIdxMap;  // a map from atom id in omol to the new atoms id in mol
  dp_mol = Subgraphs::pathToSubmol(*omol, path, false,
                                   aIdxMap);  // Using Subgraphs functionality
  d_order = path.size();

  // using aIdxMap initialize the location (and their IDs) of the
  // functional groups on dp_mol
  for (const auto &mvtci : aidToFid) {
    int oldAid = mvtci.first;
    if (aIdxMap.find(oldAid) != aIdxMap.end()) {
      int newAid = aIdxMap[oldAid];
      if (d_aToFmap.find(newAid) != d_aToFmap.end()) {
        d_aToFmap[newAid].push_back(mvtci.second);
      } else {
        INT_VECT tmpVect;
        tmpVect.clear();
        tmpVect.push_back(mvtci.second);
        d_aToFmap[newAid] = tmpVect;
      }
    }
  }
  dp_props = new Dict();

  d_descrip = "";
}
Beispiel #3
0
void FragCatalogEntry::toStream(std::ostream &ss) const {
  MolPickler::pickleMol(*dp_mol, ss);

  std::int32_t tmpInt;
  tmpInt = getBitId();
  streamWrite(ss, tmpInt);

  tmpInt = d_descrip.size();
  streamWrite(ss, tmpInt);
  ss.write(d_descrip.c_str(), tmpInt * sizeof(char));

  tmpInt = d_order;
  streamWrite(ss, tmpInt);

  tmpInt = d_aToFmap.size();
  streamWrite(ss, tmpInt);
  for (const auto &iivmci : d_aToFmap) {
    tmpInt = iivmci.first;
    streamWrite(ss, tmpInt);
    INT_VECT tmpVect = iivmci.second;
    tmpInt = tmpVect.size();
    streamWrite(ss, tmpInt);
    for (INT_VECT_CI ivci = tmpVect.begin(); ivci != tmpVect.end(); ivci++) {
      tmpInt = *ivci;
      streamWrite(ss, tmpInt);
    }
  }
}
Beispiel #4
0
void makeRingNeighborMap(const VECT_INT_VECT &brings,
                         INT_INT_VECT_MAP &neighMap, unsigned int maxSize) {
  int nrings = rdcast<int>(brings.size());
  int i, j;
  INT_VECT ring1;
  for (i = 0; i < nrings; i++) {
    INT_VECT neighs;
    neighMap[i] = neighs;
  }

  for (i = 0; i < nrings; i++) {
    if (maxSize && brings[i].size() > maxSize) continue;
    ring1 = brings[i];
    for (j = i + 1; j < nrings; j++) {
      if (maxSize && brings[j].size() > maxSize) continue;
      INT_VECT inter;
      Intersect(ring1, brings[j], inter);
      if (inter.size() > 0) {
        neighMap[i].push_back(j);
        neighMap[j].push_back(i);
      }
    }
  }
#if 0
    for (i = 0; i < nrings; i++) {
      std::cerr<<"**************\n    "<<i<<"\n*************\n";
      std::copy(neighMap[i].begin(),neighMap[i].end(),std::ostream_iterator<int>(std::cerr," "));
      std::cerr<<"\n";
    }
#endif
}
Beispiel #5
0
  const std::string GetMolFileQueryInfo(const RWMol &mol){
    std::stringstream ss;
    boost::dynamic_bitset<> listQs(mol.getNumAtoms());
    for(ROMol::ConstAtomIterator atomIt=mol.beginAtoms();
	atomIt!=mol.endAtoms();++atomIt){
      if(hasListQuery(*atomIt)) listQs.set((*atomIt)->getIdx());
    }    
    for(ROMol::ConstAtomIterator atomIt=mol.beginAtoms();
	atomIt!=mol.endAtoms();++atomIt){
      if(!listQs[(*atomIt)->getIdx()] && hasComplexQuery(*atomIt)){
	std::string sma=SmartsWrite::GetAtomSmarts(static_cast<const QueryAtom *>(*atomIt));
	ss<< "V  "<<std::setw(3)<<(*atomIt)->getIdx()+1<<" "<<sma<<std::endl;
      }
    }

    for(ROMol::ConstAtomIterator atomIt=mol.beginAtoms();
	atomIt!=mol.endAtoms();++atomIt){
      if(listQs[(*atomIt)->getIdx()]){
        INT_VECT vals;
        getListQueryVals((*atomIt)->getQuery(),vals);
        ss<<"M  ALS "<<std::setw(3)<<(*atomIt)->getIdx()+1<<" ";
        ss<<std::setw(2)<<vals.size();
        if((*atomIt)->getQuery()->getNegation()){
          ss<<" T";
        } else {
          ss<<" F";
        }
        BOOST_FOREACH(int val,vals){
          ss<<" "<<std::setw(3)<<std::left<<(PeriodicTable::getTable()->getElementSymbol(val));
        }
        ss<<"\n";
      }

    }
Beispiel #6
0
void FragCatalogEntry::setDescription(const FragCatParams *params) {
  PRECONDITION(params, "");
  INT_INT_VECT_MAP::const_iterator fMapIt;
  for (fMapIt = d_aToFmap.begin(); fMapIt != d_aToFmap.end(); fMapIt++) {
    int atIdx = fMapIt->first;
    INT_VECT fGroups = fMapIt->second;
    std::string label = "", temp;

    INT_VECT::const_iterator fGroupIdx = fGroups.begin();
    const ROMol *fGroup;
    for (unsigned int i = 0; i < fGroups.size() - 1; i++) {
      fGroup = params->getFuncGroup(*fGroupIdx);
      fGroup->getProp(common_properties::_Name, temp);
      label += "(<" + temp + ">)";
      fGroupIdx++;
    }
    fGroup = params->getFuncGroup(*fGroupIdx);
    fGroup->getProp(common_properties::_Name, temp);
    label += "<" + temp + ">";
    dp_mol->getAtomWithIdx(atIdx)
        ->setProp(common_properties::_supplementalSmilesLabel, label);
  }
  std::string smi = MolToSmiles(*dp_mol);
  // std::cerr << "----" << smi << "----" << std::endl;
  d_descrip = smi;
};
Beispiel #7
0
  INT_VECT GetBitFuncGroupIds(const FragCatalog *self,unsigned int idx){
    if(idx > self->getFPLength())
      throw_index_error(idx);
    INT_VECT res;
    INT_INT_VECT_MAP gps = self->getEntryWithBitId(idx)->getFuncGroupMap();
    for(INT_INT_VECT_MAP::const_iterator i=gps.begin();i!=gps.end();i++){
      for(INT_VECT_CI ivci=i->second.begin();ivci!=i->second.end();ivci++){
	res.push_back(*ivci);
      }
    }
    return res;
  }
Beispiel #8
0
 INT_VECT next() {
   INT_VECT res;
   if (d_pos >= (0x1u << d_questions.size())) {
     return res;
   }
   for (unsigned int i = 0; i < d_questions.size(); ++i) {
     if (d_pos & (0x1u << i)) {
       res.push_back(d_questions[i]);
     }
   }
   ++d_pos;
   return res;
 };
Beispiel #9
0
void kekulizeFused(RWMol &mol, const VECT_INT_VECT &arings,
                   unsigned int maxBackTracks) {
  // get all the atoms in the ring system
  INT_VECT allAtms;
  Union(arings, allAtms);

  // get all the atoms that are candidates to receive a double bond
  // also mark atoms in the fused system that are not aromatic to begin with
  // as done. Mark all the bonds that are part of the aromatic system
  // to be single bonds
  INT_VECT done;
  INT_VECT questions;
  unsigned int nats = mol.getNumAtoms();
  unsigned int nbnds = mol.getNumBonds();
  boost::dynamic_bitset<> dBndCands(nats);
  boost::dynamic_bitset<> dBndAdds(nbnds);

  markDbondCands(mol, allAtms, dBndCands, questions, done);
#if 0
      std::cerr << "candidates: ";
      for(int i=0;i<nats;++i) std::cerr << dBndCands[i];
      std::cerr << std::endl;
#endif

  bool kekulized;
  kekulized =
      kekulizeWorker(mol, allAtms, dBndCands, dBndAdds, done, maxBackTracks);
  if (!kekulized && questions.size()) {
    // we failed, but there are some dummy atoms we can try permuting.
    kekulized = permuteDummiesAndKekulize(mol, allAtms, dBndCands, questions,
                                          maxBackTracks);
  }
  if (!kekulized) {
    // we exhausted all option (or crossed the allowed
    // number of backTracks) and we still need to backtrack
    // can't kekulize this thing
    std::ostringstream errout;
    errout << "Can't kekulize mol.";
    errout << "  Unkekulized atoms:";
    for (unsigned int i = 0; i < nats; ++i) {
      if (dBndCands[i]) errout << " " << i;
    }
    errout << std::endl;
    std::string msg = errout.str();
    BOOST_LOG(rdErrorLog) << msg << std::endl;
    throw MolSanitizeException(msg);
  }
}
Beispiel #10
0
  int nextCombination(INT_VECT &comb, int tot) {
    int nelem = static_cast<int>(comb.size());
    int celem = nelem - 1;
    
    while (comb[celem] == (tot - nelem + celem)) {
      celem--;
      if (celem < 0) {
	return -1;
      }
    }

    unsigned int i;
    comb[celem] += 1;
    for (i = celem+1; i < comb.size(); i++) {
      comb[i] = comb[i-1] + 1;
    }
    return celem;
  }
Beispiel #11
0
  void Intersect(const INT_VECT &r1, const INT_VECT &r2, INT_VECT &res) {
    res.resize(0);
    INT_VECT_CI ri;
    for (ri = r1.begin(); ri != r1.end(); ri++) {
      if (std::find(r2.begin(), r2.end(), (*ri)) != r2.end()){
	res.push_back(*ri);
      }
    }
  }
Beispiel #12
0
void pickFusedRings(int curr, const INT_INT_VECT_MAP &neighMap, INT_VECT &res,
                    boost::dynamic_bitset<> &done, int depth) {
  INT_INT_VECT_MAP::const_iterator pos = neighMap.find(curr);
  PRECONDITION(pos != neighMap.end(), "bad argument");
  done[curr] = 1;
  res.push_back(curr);

  const INT_VECT &neighs = pos->second;
#if 0
    std::cerr<<"depth: "<<depth<<" ring: "<<curr<<" size: "<<res.size()<<" neighs: "<<neighs.size()<<std::endl;
    std::cerr<<"   ";
    std::copy(neighs.begin(),neighs.end(),std::ostream_iterator<int>(std::cerr," "));
    std::cerr<<"\n";
#endif
  for (INT_VECT_CI ni = neighs.begin(); ni != neighs.end(); ++ni) {
    if (!done[*ni]) {
      pickFusedRings((*ni), neighMap, res, done, depth + 1);
    }
  }
}
Beispiel #13
0
  void Union(const INT_VECT &r1, const INT_VECT &r2, INT_VECT &res) {
    res.resize(0);
    res = r1;
    INT_VECT_CI ri;
    for (ri = r2.begin(); ri != r2.end(); ri++) {
      if (std::find(res.begin(), res.end(), (*ri)) == res.end()){
	res.push_back(*ri);
      }
    }
  }
  ROMol *prepareMol(const ROMol &mol, const FragCatParams *fparams,
		    MatchVectType &aToFmap) {
    PRECONDITION(fparams,"");
    
    // get a mapping of the functional groups onto the molecule
    INT_VECT fgBonds;
    MatchVectType aidToFid = findFuncGroupsOnMol(mol, fparams, fgBonds);
    
    // get the core piece of molecule (i.e. the part of the molecule 
    // without the functional groups). This basically the part of the molecule
    // that does not contain the function group bonds given by "fgBonds"
    INT_VECT cBonds;
    int bid, nbds = mol.getNumBonds();

    for (bid = 0; bid < nbds; bid++) {
      if (std::find(fgBonds.begin(), fgBonds.end(), bid) == fgBonds.end()) {
	cBonds.push_back(bid);
      }
    }

    INT_MAP_INT aIdxMap; // a map from atom id in mol to the new atoms id in coreMol
    
    ROMol *coreMol = Subgraphs::pathToSubmol(mol, cBonds, false, aIdxMap);
    
    // now map the functional groups on mol to coreMol using aIdxMap
    MatchVectType::iterator mati;
    
    int newID;
    for (mati = aidToFid.begin(); mati != aidToFid.end(); mati++) {
      newID = aIdxMap[mati->first];
      aToFmap.push_back(std::pair<int, int>(newID, mati->second));
    }
    
    return coreMol;
  }
Beispiel #15
0
void FragCatalogEntry::initFromStream(std::istream &ss) {
  // the molecule:
  dp_mol = new ROMol();
  MolPickler::molFromPickle(ss, *dp_mol);

  std::int32_t tmpInt;
  // the bitId:
  streamRead(ss, tmpInt);
  setBitId(tmpInt);

  // the description:
  streamRead(ss, tmpInt);
  auto *tmpText = new char[tmpInt + 1];
  ss.read(tmpText, tmpInt * sizeof(char));
  tmpText[tmpInt] = 0;
  d_descrip = tmpText;
  delete[] tmpText;

  streamRead(ss, tmpInt);
  d_order = tmpInt;

  // now the map:
  streamRead(ss, tmpInt);
  for (int i = 0; i < tmpInt; i++) {
    std::int32_t key, value, size;
    streamRead(ss, key);
    streamRead(ss, size);
    INT_VECT tmpVect;
    tmpVect.clear();
    for (int j = 0; j < size; j++) {
      streamRead(ss, value);
      tmpVect.push_back(value);
    }
    d_aToFmap[key] = tmpVect;
  }
}
Beispiel #16
0
  /*! \brief split the formal charge across atoms of same type if we have a conjugated system
   *
   *  This function is called before the charge equivalization iteration is started for the 
   *  Gasteiger charges. If any of the atom involved in conjugated system have formal charges 
   *  set on them, this charges is equally distributed across atoms of the same type in that
   *  conjugated system. So for example the two nitrogens in the benzamidine system start the iteration
   * with equal charges of 0.5
   */
  void splitChargeConjugated(const ROMol &mol, DOUBLE_VECT &charges) {
    int aix;
    int natms = mol.getNumAtoms();
    INT_VECT marker;
    INT_VECT_CI mci;
    int aax, yax;
    double formal;
    const Atom *at, *aat, *yat;
    for (aix = 0; aix < natms; aix++) {
      at = mol.getAtomWithIdx(aix);
      formal = at->getFormalCharge();
      //std::cout << aix << " formal charges:" << formal << "\n";
      marker.resize(0);
      if ((fabs(formal) > EPS_DOUBLE)  && (fabs(charges[aix]) < EPS_DOUBLE) ) {
        marker.push_back(aix);
        ROMol::OEDGE_ITER bnd1, end1, bnd2, end2;
        boost::tie(bnd1,end1) = mol.getAtomBonds(at);
        while (bnd1 != end1) {
          if (mol[*bnd1]->getIsConjugated()) {
            aax = mol[*bnd1]->getOtherAtomIdx(aix);
            aat = mol.getAtomWithIdx(aax);
            boost::tie(bnd2,end2) = mol.getAtomBonds(aat);
            while (bnd2 != end2) {
              if ((*bnd1) != (*bnd2)) {
                if (mol[*bnd2]->getIsConjugated()) {
                  yax = mol[*bnd2]->getOtherAtomIdx(aax);
                  yat = mol.getAtomWithIdx(yax);
                  if (at->getAtomicNum() == yat->getAtomicNum()) {
                    formal += yat->getFormalCharge();
                    marker.push_back(yax);
                  }
                }
              }
              bnd2++;
            }
          }
          bnd1++;
        }

        for (mci = marker.begin(); mci != marker.end(); mci++) {
          charges[*mci] = (formal/marker.size());
        }
      }
    }
    /*
    for (aix = 0; aix < natms; aix++) {
      std::cout << "In splitter: " << " charges:" << charges[aix] << "\n";
      }*/
  }            
Beispiel #17
0
bool permuteDummiesAndKekulize(RWMol &mol, const INT_VECT &allAtms,
                               boost::dynamic_bitset<> dBndCands,
                               INT_VECT &questions,
                               unsigned int maxBackTracks) {
  boost::dynamic_bitset<> atomsInPlay(mol.getNumAtoms());
  for (int allAtm : allAtms) {
    atomsInPlay[allAtm] = 1;
  }
  bool kekulized = false;
  QuestionEnumerator qEnum(questions);
  while (!kekulized && questions.size()) {
    boost::dynamic_bitset<> dBndAdds(mol.getNumBonds());
    INT_VECT done;
#if 1
    // reset the state: all aromatic bonds are remarked to single:
    for (RWMol::BondIterator bi = mol.beginBonds(); bi != mol.endBonds();
         ++bi) {
      if ((*bi)->getIsAromatic() && (*bi)->getBondType() != Bond::SINGLE &&
          atomsInPlay[(*bi)->getBeginAtomIdx()] &&
          atomsInPlay[(*bi)->getEndAtomIdx()]) {
        (*bi)->setBondType(Bond::SINGLE);
      }
    }
#endif
    // pick a new permutation of the questionable atoms:
    const INT_VECT &switchOff = qEnum.next();
    if (!switchOff.size()) break;
    boost::dynamic_bitset<> tCands = dBndCands;
    for (int it : switchOff) {
      tCands[it] = 0;
    }
#if 0
        std::cerr<<"permute: ";
        for (boost::dynamic_bitset<>::size_type i = 0; i < tCands.size(); ++i){
          std::cerr << tCands[i];
        }
        std::cerr<<std::endl;
#endif
    // try kekulizing again:
    kekulized =
        kekulizeWorker(mol, allAtms, tCands, dBndAdds, done, maxBackTracks);
  }
  return kekulized;
}
Beispiel #18
0
bool checkFused(const INT_VECT &rids, INT_INT_VECT_MAP &ringNeighs) {
  INT_INT_VECT_MAP_CI nci;
  int nrings = rdcast<int>(ringNeighs.size());
  boost::dynamic_bitset<> done(nrings);
  int rid;
  INT_VECT fused;

  // mark all rings in the system other than those in rids as done
  for (nci = ringNeighs.begin(); nci != ringNeighs.end(); nci++) {
    rid = (*nci).first;
    if (std::find(rids.begin(), rids.end(), rid) == rids.end()) {
      done[rid] = 1;
    }
  }

  // then pick a fused system from the remaining (i.e. rids)
  // If the rings in rids are fused we should get back all of them
  // in fused
  // if we get a smaller number in fused then rids are not fused
  pickFusedRings(rids.front(), ringNeighs, fused, done);

  CHECK_INVARIANT(fused.size() <= rids.size(), "");
  return (fused.size() == rids.size());
}
Beispiel #19
0
  void Union(const VECT_INT_VECT &rings, INT_VECT &res, const INT_VECT *exclude) {
    res.resize(0);
    INT_VECT ring;
    unsigned int id;
    unsigned int nrings = static_cast<unsigned int>(rings.size());
    INT_VECT_CI ri;
    
    for (id = 0; id < nrings; id++) {
      if (exclude) {
	if (std::find(exclude->begin(), exclude->end(), static_cast<int>(id)) != exclude->end()) {
	  continue;
	}
      }
      ring = rings[id];
      for (ri = ring.begin(); ri != ring.end(); ri++) {
	if (std::find(res.begin(), res.end(), (*ri)) == res.end()) {
	  res.push_back(*ri);
	}
      }
    }
  }
Beispiel #20
0
 void getListQueryVals(const Atom::QUERYATOM_QUERY *q,INT_VECT &vals){
   // list queries are series of nested ors of AtomAtomicNum queries
   PRECONDITION(q,"bad query");
   std::string descr=q->getDescription();
   PRECONDITION(descr=="AtomOr","bad query");
   if(descr=="AtomOr"){
     for(Atom::QUERYATOM_QUERY::CHILD_VECT_CI cIt=q->beginChildren();
         cIt!=q->endChildren();++cIt){
       std::string descr=(*cIt)->getDescription();
       CHECK_INVARIANT((descr=="AtomOr"||descr=="AtomAtomicNum"),"bad query");
       // we don't allow negation of any children of the query:
       if(descr=="AtomOr"){
         getListQueryVals((*cIt).get(),vals);
       } else if(descr=="AtomAtomicNum"){
         vals.push_back(static_cast<ATOM_EQUALS_QUERY *>((*cIt).get())->getVal());
       }
     }
   }
 }
Beispiel #21
0
  void canonicalDFSTraversal(ROMol &mol,int atomIdx,int inBondIdx,
                             std::vector<AtomColors> &colors,
                             VECT_INT_VECT &cycles,
                             INT_VECT &ranks,
                             INT_VECT &cyclesAvailable,
                             MolStack &molStack,
                             INT_VECT &atomOrders,
                             INT_VECT &bondVisitOrders,
                             VECT_INT_VECT &atomRingClosures,
                             std::vector<INT_LIST> &atomTraversalBondOrder,
                             const boost::dynamic_bitset<> *bondsInPlay,
                             const std::vector<std::string> *bondSymbols
                             ){
    PRECONDITION(colors.size()>=mol.getNumAtoms(),"vector too small");
    PRECONDITION(ranks.size()>=mol.getNumAtoms(),"vector too small");
    PRECONDITION(atomOrders.size()>=mol.getNumAtoms(),"vector too small");
    PRECONDITION(bondVisitOrders.size()>=mol.getNumBonds(),"vector too small");
    PRECONDITION(atomRingClosures.size()>=mol.getNumAtoms(),"vector too small");
    PRECONDITION(atomTraversalBondOrder.size()>=mol.getNumAtoms(),"vector too small");
    PRECONDITION(!bondsInPlay || bondsInPlay->size()>=mol.getNumBonds(),"bondsInPlay too small");
    PRECONDITION(!bondSymbols || bondSymbols->size()>=mol.getNumBonds(),"bondSymbols too small");

    int nAttached=0;

    Atom *atom = mol.getAtomWithIdx(atomIdx);
    INT_LIST directTravList,cycleEndList;

    molStack.push_back(MolStackElem(atom));
    atomOrders[atom->getIdx()] = molStack.size();
    colors[atomIdx] = GREY_NODE;

    // ---------------------
    //
    //  Build the list of possible destinations from here
    //
    // ---------------------
    std::vector< PossibleType > possibles;
    possibles.resize(0);
    ROMol::OBOND_ITER_PAIR bondsPair = mol.getAtomBonds(atom);
    possibles.reserve(bondsPair.second-bondsPair.first);

    while(bondsPair.first != bondsPair.second){
      BOND_SPTR theBond = mol[*(bondsPair.first)];
      bondsPair.first++;
      if(bondsInPlay && !(*bondsInPlay)[theBond->getIdx()]) continue;
      if(inBondIdx<0 || theBond->getIdx() != static_cast<unsigned int>(inBondIdx)){
        int otherIdx = theBond->getOtherAtomIdx(atomIdx);
        long rank=ranks[otherIdx];
        // ---------------------
        //
        // things are a bit more complicated if we are sitting on a
        // ring atom we would like to traverse first to the
        // ring-closure atoms, then to atoms outside the ring first,
        // then to atoms in the ring that haven't already been visited
        // (non-ring-closure atoms).
        // 
        //  Here's how the black magic works:
        //   - non-ring atom neighbors have their original ranks
        //   - ring atom neighbors have this added to their ranks:
        //       (Bond::OTHER - bondOrder)*MAX_NATOMS*MAX_NATOMS
        //   - ring-closure neighbors lose a factor of:
        //       (Bond::OTHER+1)*MAX_NATOMS*MAX_NATOMS
        //
        //  This tactic biases us to traverse to non-ring neighbors first,
        //  original ordering if bond orders are all equal... crafty, neh?
        //  
        // ---------------------
        if( colors[otherIdx] == GREY_NODE ) {
          rank -= static_cast<int>(Bond::OTHER+1) *
            MAX_NATOMS*MAX_NATOMS;
          if(!bondSymbols){
            rank += static_cast<int>(Bond::OTHER - theBond->getBondType()) *
              MAX_NATOMS;
          } else {
            const std::string &symb=(*bondSymbols)[theBond->getIdx()];
            boost::uint32_t hsh=gboost::hash_range(symb.begin(),symb.end());
            rank += (hsh%MAX_NATOMS) *  MAX_NATOMS;
          }
        } else if( theBond->getOwningMol().getRingInfo()->numBondRings(theBond->getIdx()) ){
          if(!bondSymbols){
            rank += static_cast<int>(Bond::OTHER - theBond->getBondType()) *
              MAX_NATOMS*MAX_NATOMS;
          } else {
            const std::string &symb=(*bondSymbols)[theBond->getIdx()];
            boost::uint32_t hsh=gboost::hash_range(symb.begin(),symb.end());
            rank += (hsh%MAX_NATOMS)*MAX_NATOMS*MAX_NATOMS;
          }
        }
        possibles.push_back(PossibleType(rank,otherIdx,theBond.get()));
      }
    }

    // ---------------------
    //
    //  Sort on ranks
    //
    // ---------------------
    std::sort(possibles.begin(),possibles.end(),_possibleComp);


    // ---------------------
    //
    //  Now work the children
    //
    // ---------------------
    std::vector<MolStack> subStacks;
    for(std::vector<PossibleType>::iterator possiblesIt=possibles.begin();
        possiblesIt!=possibles.end();
        possiblesIt++){
      MolStack subStack;
#if 0
      int possibleIdx = possiblesIt->second.first;
      Bond *bond = possiblesIt->second.second;
#endif
      int possibleIdx = possiblesIt->get<1>();
      Bond *bond = possiblesIt->get<2>();
      Atom *otherAtom=mol.getAtomWithIdx(possibleIdx);
      unsigned int lowestRingIdx;
      INT_VECT::const_iterator cAIt;
      switch(colors[possibleIdx]){
      case WHITE_NODE:
        // -----
        // we haven't seen this node at all before
        // -----

        // it might have some residual data from earlier calls, clean that up:
        if(otherAtom->hasProp("_TraversalBondIndexOrder")){
          otherAtom->clearProp("_TraversalBondIndexOrder");
        }

        directTravList.push_back(bond->getIdx());
        subStack.push_back(MolStackElem(bond,atomIdx));
        canonicalDFSTraversal(mol,possibleIdx,bond->getIdx(),colors,
                              cycles,ranks,cyclesAvailable,subStack,
                              atomOrders,bondVisitOrders,atomRingClosures,atomTraversalBondOrder,
                              bondsInPlay,bondSymbols);
        subStacks.push_back(subStack);
        nAttached += 1;
        break;
      case GREY_NODE:
        // -----
        // we've seen this, but haven't finished it (we're finishing a ring)
        // -----
        cycleEndList.push_back(bond->getIdx());
        cAIt=std::find(cyclesAvailable.begin(),
                       cyclesAvailable.end(),1);
        if(cAIt==cyclesAvailable.end()){
          throw ValueErrorException("Too many rings open at once. SMILES cannot be generated.");
        }
        lowestRingIdx =  cAIt-cyclesAvailable.begin();
        cyclesAvailable[lowestRingIdx] = 0;
        cycles[possibleIdx].push_back(lowestRingIdx);
        ++lowestRingIdx;

        bond->setProp("_TraversalRingClosureBond",lowestRingIdx);
        molStack.push_back(MolStackElem(bond,
                                        atom->getIdx()));
        molStack.push_back(MolStackElem(lowestRingIdx));

        // we need to add this bond (which closes the ring) to the traversal list for the
        // other atom as well:
        atomTraversalBondOrder[otherAtom->getIdx()].push_back(bond->getIdx());
        atomRingClosures[otherAtom->getIdx()].push_back(bond->getIdx());

        break;
      default:
        // -----
        // this node has been finished. don't do anything.
        // -----
        break;
      }
    }
    

    INT_VECT &ringClosures=atomRingClosures[atom->getIdx()];
    
    CHECK_INVARIANT(ringClosures.size()==cycles[atomIdx].size(),
                    "ring closure mismatch");
    for(unsigned int i=0;i<ringClosures.size();i++){
      int ringIdx=cycles[atomIdx][i];
      ringIdx += 1;
      molStack.push_back(MolStackElem(ringIdx));
    }
    cycles[atomIdx].resize(0);
  
    MolStack::const_iterator ciMS;
    for(int i=0;i<nAttached;i++){
      if(i<nAttached-1){
        int branchIdx=0;
        if(subStacks[i].begin()->type==MOL_STACK_ATOM){
          branchIdx=subStacks[i].begin()->obj.atom->getIdx();
        } else if(subStacks[i].begin()->type==MOL_STACK_BOND){
          branchIdx=-1*subStacks[i].begin()->obj.bond->getIdx();
        } else {
          ASSERT_INVARIANT(0,"branch started with something other than an atom or bond");
        }
        molStack.push_back(MolStackElem("(",branchIdx));
        for(ciMS=subStacks[i].begin();ciMS!=subStacks[i].end();ciMS++){
          molStack.push_back(*ciMS);
          switch(ciMS->type){
          case MOL_STACK_ATOM:
            atomOrders[ciMS->obj.atom->getIdx()] = molStack.size();
            break;
          case MOL_STACK_BOND:
            bondVisitOrders[ciMS->obj.bond->getIdx()] = molStack.size();
            break;
          default:
            break;
          }
        }
        molStack.push_back(MolStackElem(")",branchIdx));
      } else {
        for(ciMS=subStacks[i].begin();ciMS!=subStacks[i].end();ciMS++){
          molStack.push_back(*ciMS);
          switch(ciMS->type){
          case MOL_STACK_ATOM:
            atomOrders[ciMS->obj.atom->getIdx()] = molStack.size();
            break;
          case MOL_STACK_BOND:
            bondVisitOrders[ciMS->obj.bond->getIdx()] = molStack.size();
            break;
          default:
            break;
          }
        }
      }
    }

    //std::cerr<<"*****>>>>>> Traversal results for atom: "<<atom->getIdx()<<"> ";
    INT_LIST travList;
    // first push on the incoming bond:
    if(inBondIdx >= 0){
      //std::cerr<<" "<<inBondIdx;
      travList.push_back(inBondIdx);
    }

    // ... ring closures that end here:
    for(INT_LIST_CI ilci=cycleEndList.begin();ilci!=cycleEndList.end();++ilci){
      //std::cerr<<" ["<<*ilci<<"]";
      travList.push_back(*ilci);
    }


    // ... ring closures that start here:
    // if(atom->hasProp("_TraversalBondIndexOrder")){
    //   INT_LIST indirectTravList;
    //   atom->getProp("_TraversalBondIndexOrder",indirectTravList);
    //   for(INT_LIST_CI ilci=indirectTravList.begin();ilci!=indirectTravList.end();++ilci){
    //     //std::cerr<<" ("<<*ilci<<")";
    //     travList.push_back(*ilci);
    //   }
    // }
    BOOST_FOREACH(int ili,atomTraversalBondOrder[atom->getIdx()]){
      travList.push_back(ili);
    }
Beispiel #22
0
  void dfsBuildStack(ROMol &mol,int atomIdx,int inBondIdx,
                     std::vector<AtomColors> &colors,
                     VECT_INT_VECT &cycles,
                     const UINT_VECT &ranks,
                     INT_VECT &cyclesAvailable,
                     MolStack &molStack,
                     INT_VECT &atomOrders,
                     INT_VECT &bondVisitOrders,
                     VECT_INT_VECT &atomRingClosures,
                     std::vector<INT_LIST> &atomTraversalBondOrder,
                     const boost::dynamic_bitset<> *bondsInPlay,
                     const std::vector<std::string> *bondSymbols
                     ){
#if 0
    std::cerr<<"traverse from atom: "<<atomIdx<<" via bond "<<inBondIdx<<" num cycles available: "
             <<std::count(cyclesAvailable.begin(),cyclesAvailable.end(),1)<<std::endl;
#endif
    Atom *atom = mol.getAtomWithIdx(atomIdx);
    INT_LIST directTravList,cycleEndList;
    boost::dynamic_bitset<> seenFromHere(mol.getNumAtoms());
    
    seenFromHere.set(atomIdx);
    molStack.push_back(MolStackElem(atom));
    atomOrders[atom->getIdx()] = molStack.size();
    colors[atomIdx] = GREY_NODE;

    INT_LIST travList;
    if(inBondIdx>=0) travList.push_back(inBondIdx);

    
    // ---------------------
    //
    //  Add any ring closures
    //
    // ---------------------
    if(atomRingClosures[atomIdx].size()){
      std::vector<unsigned int> ringsClosed;
      BOOST_FOREACH(int bIdx,atomRingClosures[atomIdx]){
        travList.push_back(bIdx);
        Bond *bond = mol.getBondWithIdx(bIdx);
        seenFromHere.set(bond->getOtherAtomIdx(atomIdx));
        unsigned int ringIdx;
        if(bond->getPropIfPresent(common_properties::_TraversalRingClosureBond, ringIdx)){
          // this is end of the ring closure
          // we can just pull the ring index from the bond itself:
          molStack.push_back(MolStackElem(bond,atomIdx));
          bondVisitOrders[bIdx]=molStack.size();
          molStack.push_back(MolStackElem(ringIdx));
          // don't make the ring digit immediately available again: we don't want to have the same
          // ring digit opening and closing rings on an atom.
          ringsClosed.push_back(ringIdx-1);
        } else {
          // this is the beginning of the ring closure, we need to come up with a ring index:
          INT_VECT::const_iterator cAIt=std::find(cyclesAvailable.begin(),
                                                  cyclesAvailable.end(),1);
          if(cAIt==cyclesAvailable.end()){
            throw ValueErrorException("Too many rings open at once. SMILES cannot be generated.");
          }
          unsigned int lowestRingIdx =  cAIt-cyclesAvailable.begin();
          cyclesAvailable[lowestRingIdx] = 0;
          ++lowestRingIdx;
          bond->setProp(common_properties::_TraversalRingClosureBond,lowestRingIdx);
          molStack.push_back(MolStackElem(lowestRingIdx));
        }
      }
Beispiel #23
0
  // finds cycles
  void dfsFindCycles(ROMol &mol,int atomIdx,int inBondIdx,
                     std::vector<AtomColors> &colors,
                     const UINT_VECT &ranks,
                     INT_VECT &atomOrders,
                     VECT_INT_VECT &atomRingClosures,
                     const boost::dynamic_bitset<> *bondsInPlay,
                     const std::vector<std::string> *bondSymbols
                     ){
    Atom *atom = mol.getAtomWithIdx(atomIdx);
    atomOrders.push_back(atomIdx);

    colors[atomIdx] = GREY_NODE;

    // ---------------------
    //
    //  Build the list of possible destinations from here
    //
    // ---------------------
    std::vector< PossibleType > possibles;
    possibles.resize(0);
    ROMol::OBOND_ITER_PAIR bondsPair = mol.getAtomBonds(atom);
    possibles.reserve(bondsPair.second-bondsPair.first);

    while(bondsPair.first != bondsPair.second){
      BOND_SPTR theBond = mol[*(bondsPair.first)];
      bondsPair.first++;
      if(bondsInPlay && !(*bondsInPlay)[theBond->getIdx()]) continue;
      if(inBondIdx<0 || theBond->getIdx() != static_cast<unsigned int>(inBondIdx)){
        int otherIdx = theBond->getOtherAtomIdx(atomIdx);
        long rank=ranks[otherIdx];
        // ---------------------
        //
        // things are a bit more complicated if we are sitting on a
        // ring atom. we would like to traverse first to the
        // ring-closure atoms, then to atoms outside the ring first,
        // then to atoms in the ring that haven't already been visited
        // (non-ring-closure atoms).
        // 
        //  Here's how the black magic works:
        //   - non-ring atom neighbors have their original ranks
        //   - ring atom neighbors have this added to their ranks:
        //       (MAX_BONDTYPE - bondOrder)*MAX_NATOMS*MAX_NATOMS
        //   - ring-closure neighbors lose a factor of:
        //       (MAX_BONDTYPE+1)*MAX_NATOMS*MAX_NATOMS
        //
        //  This tactic biases us to traverse to non-ring neighbors first,
        //  original ordering if bond orders are all equal... crafty, neh?
        //  
        // ---------------------
        if( colors[otherIdx] == GREY_NODE ) {
          rank -= static_cast<int>(MAX_BONDTYPE+1) *
            MAX_NATOMS*MAX_NATOMS;
          if(!bondSymbols){
            rank += static_cast<int>(MAX_BONDTYPE - theBond->getBondType()) *
              MAX_NATOMS;
          } else {
            const std::string &symb=(*bondSymbols)[theBond->getIdx()];
            boost::uint32_t hsh=gboost::hash_range(symb.begin(),symb.end());
            rank += (hsh%MAX_NATOMS) *  MAX_NATOMS;
          }
        } else if( theBond->getOwningMol().getRingInfo()->numBondRings(theBond->getIdx()) ){
          if(!bondSymbols){
            rank += static_cast<int>(MAX_BONDTYPE - theBond->getBondType()) *
              MAX_NATOMS*MAX_NATOMS;
          } else {
            const std::string &symb=(*bondSymbols)[theBond->getIdx()];
            boost::uint32_t hsh=gboost::hash_range(symb.begin(),symb.end());
            rank += (hsh%MAX_NATOMS)*MAX_NATOMS*MAX_NATOMS;
          }
        }
       //std::cerr<<"aIdx: "<< atomIdx <<"   p: "<<otherIdx<<" Rank: "<<ranks[otherIdx] <<" "<<colors[otherIdx]<<" "<<theBond->getBondType()<<" "<<rank<<std::endl;
        possibles.push_back(PossibleType(rank,otherIdx,theBond.get()));
      }
    }

    // ---------------------
    //
    //  Sort on ranks
    //
    // ---------------------
    std::sort(possibles.begin(),possibles.end(),_possibleCompare());


    // ---------------------
    //
    //  Now work the children
    //
    // ---------------------
    for(std::vector<PossibleType>::iterator possiblesIt=possibles.begin();
        possiblesIt!=possibles.end();
        possiblesIt++){
      int possibleIdx = possiblesIt->get<1>();
      Bond *bond = possiblesIt->get<2>();
      Atom *otherAtom=mol.getAtomWithIdx(possibleIdx);
      switch(colors[possibleIdx]){
      case WHITE_NODE:
        // -----
        // we haven't seen this node at all before, traverse
        // -----
        dfsFindCycles(mol,possibleIdx,bond->getIdx(),colors,
                    ranks,atomOrders,
                    atomRingClosures,
                    bondsInPlay,bondSymbols);
        break;
      case GREY_NODE:
        // -----
        // we've seen this, but haven't finished it (we're finishing a ring)
        // -----
        atomRingClosures[possibleIdx].push_back(bond->getIdx());
        atomRingClosures[atomIdx].push_back(bond->getIdx());
        break;
      default:
        // -----
        // this node has been finished. don't do anything.
        // -----
        break;
      }
    }
    colors[atomIdx] = BLACK_NODE;
  }
Beispiel #24
0
int setAromaticity(RWMol &mol) {
  // FIX: we will assume for now that if the input molecule came
  // with aromaticity information it is correct and we will not
  // touch it. Loop through the atoms and check if any atom has
  // arom stuff set.  We may want check this more carefully later
  // and start from scratch if necessary
  ROMol::AtomIterator ai;
  for (ai = mol.beginAtoms(); ai != mol.endAtoms(); ai++) {
    if ((*ai)->getIsAromatic()) {
      // found aromatic info
      return -1;
    }
  }

  // first find the all the simple rings in the molecule
  VECT_INT_VECT srings;
  if (mol.getRingInfo()->isInitialized()) {
    srings = mol.getRingInfo()->atomRings();
  } else {
    MolOps::symmetrizeSSSR(mol, srings);
  }

  int narom = 0;
  // loop over all the atoms in the rings that can be candidates
  // for aromaticity
  // Atoms are candidates if
  //   - it is part of ring
  //   - has one or more electron to donate or has empty p-orbitals
  int natoms = mol.getNumAtoms();
  boost::dynamic_bitset<> acands(natoms);
  boost::dynamic_bitset<> aseen(natoms);
  VECT_EDON_TYPE edon(natoms);

  VECT_INT_VECT cRings;  // holder for rings that are candidates for aromaticity
  for (VECT_INT_VECT_I vivi = srings.begin(); vivi != srings.end(); ++vivi) {
    bool allAromatic = true;
    for (INT_VECT_I ivi = (*vivi).begin(); ivi != (*vivi).end(); ++ivi) {
      if (aseen[*ivi]) {
        if (!acands[*ivi]) allAromatic = false;
        continue;
      }
      aseen[*ivi] = 1;
      Atom *at = mol.getAtomWithIdx(*ivi);

      // now that the atom is part of ring check if it can donate
      // electron or has empty orbitals. Record the donor type
      // information in 'edon' - we will need it when we get to
      // the Huckel rule later
      edon[*ivi] = getAtomDonorTypeArom(at);
      acands[*ivi] = isAtomCandForArom(at, edon[*ivi]);
      if (!acands[*ivi]) allAromatic = false;
    }
    if (allAromatic) {
      cRings.push_back((*vivi));
    }
  }

  // first convert all rings to bonds ids
  VECT_INT_VECT brings;
  RingUtils::convertToBonds(cRings, brings, mol);

  // make the neighbor map for the rings
  // i.e. a ring is a neighbor a another candidate ring if
  // shares at least one bond
  // useful to figure out fused systems
  INT_INT_VECT_MAP neighMap;
  RingUtils::makeRingNeighborMap(brings, neighMap, maxFusedAromaticRingSize);

  // now loop over all the candidate rings and check the
  // huckel rule - of course paying attention to fused systems.
  INT_VECT doneRs;
  int curr = 0;
  int cnrs = rdcast<int>(cRings.size());
  boost::dynamic_bitset<> fusDone(cnrs);
  INT_VECT fused;
  while (curr < cnrs) {
    fused.resize(0);
    RingUtils::pickFusedRings(curr, neighMap, fused, fusDone);
    applyHuckelToFused(mol, cRings, brings, fused, edon, neighMap, narom, 6);

    int rix;
    for (rix = 0; rix < cnrs; rix++) {
      if (!fusDone[rix]) {
        curr = rix;
        break;
      }
    }
    if (rix == cnrs) {
      break;
    }
  }

  mol.setProp(common_properties::numArom, narom, true);

  return narom;
}
  MatchVectType findFuncGroupsOnMol(const ROMol &mol, 
				    const FragCatParams *params,
				    INT_VECT &fgBonds) {
    PRECONDITION(params,"bad params");

    fgBonds.clear();
    
    std::pair<int, int> amat;
    MatchVectType aidFgrps;
    std::vector<MatchVectType> fgpMatches;
    std::vector<MatchVectType>::const_iterator mati;
    MatchVectType::const_iterator mi;
    int aid;
    //const ROMol *fgrp;

    INT_VECT_CI bi;
    aidFgrps.clear();
    
    int fid = 0;
    const MOL_SPTR_VECT &fgrps = params->getFuncGroups();
    MOL_SPTR_VECT::const_iterator fgci;
    
    for (fgci = fgrps.begin(); fgci != fgrps.end(); fgci++) {
      const ROMol *fgrp = fgci->get();
      std::string fname;
      (*fgci)->getProp(common_properties::_Name, fname);
      //std::cout << "Groups number: " << fname << "\n";
      //(*fgci)->debugMol(std::cout);
      //mol->debugMol(std::cout);
      // match this functional group onto the molecule
      SubstructMatch(mol, *fgrp, fgpMatches);

      // loop over all the matches we get for this fgroup
      for (mati = fgpMatches.begin(); mati != fgpMatches.end(); mati++) {
	//FIX: we will assume that the first atom in fgrp is always the connection
	// atom
	amat = mati->front();
	aid = amat.second; //FIX: is this correct - the second entry in the pair is the atom ID from mol

	// grab the list of atom Ids from mol that match the functional group 
	INT_VECT bondIds, maids;
	for (mi = mati->begin(); mi != mati->end(); mi++) {
	  maids.push_back(mi->second);
	}

	// create a list of bond IDs from these atom ID 
	// these are the bond in mol that are part of portion that matches the 
	// functional group
	bondIds = Subgraphs::bondListFromAtomList(mol, maids);
	
	// now check if all these bonds have been covered as part of larger 
	// functional group that was dealt with earlier
	// FIX: obviously we assume here that the function groups in params 
	// come in decreasing order of size.
	bool allDone = true;
	for (bi = bondIds.begin(); bi != bondIds.end(); bi++) {
	  if (std::find(fgBonds.begin(), fgBonds.end(), (*bi)) == fgBonds.end()) {
	    allDone = false;
	    fgBonds.push_back(*bi);
	  }
	}
	
	if (!allDone) {
	  // this functional group mapping onto mol is not part of a larger func
	  // group mapping so record it
	  aidFgrps.push_back(std::pair<int, int>(aid, fid));
	}
      }
      fid++;

    }

    
    return aidFgrps;
  }
Beispiel #26
0
bool kekulizeWorker(RWMol &mol, const INT_VECT &allAtms,
                    boost::dynamic_bitset<> dBndCands,
                    boost::dynamic_bitset<> dBndAdds, INT_VECT done,
                    unsigned int maxBackTracks) {
  INT_DEQUE astack;
  INT_INT_DEQ_MAP options;
  int lastOpt = -1;
  boost::dynamic_bitset<> localBondsAdded(mol.getNumBonds());

  // ok the algorithm goes something like this
  // - start with an atom that has been marked aromatic before
  // - check if it can have a double bond
  // - add its neighbors to the stack
  // - check if one of its neighbors can also have a double bond
  // - if yes add a double bond.
  // - if multiple neighbors can have double bonds - add them to a
  //   options stack we may have to retrace out path if we chose the
  //   wrong neighbor to add the double bond
  // - if double bond added update the candidates for double bond
  // - move to the next atom on the stack and repeat the process
  // - if an atom that can have multiple a double bond has no
  //   neighbors that can take double bond - we made a mistake
  //   earlier by picking a wrong candidate for double bond
  // - in this case back track to where we made the mistake

  int curr;
  INT_DEQUE btmoves;
  unsigned int numBT = 0;  // number of back tracks so far
  while ((done.size() < allAtms.size()) || (astack.size() > 0)) {
    // pick a curr atom to work with
    if (astack.size() > 0) {
      curr = astack.front();
      astack.pop_front();
    } else {
      for (int allAtm : allAtms) {
        if (std::find(done.begin(), done.end(), allAtm) == done.end()) {
          curr = allAtm;
          break;
        }
      }
    }
    done.push_back(curr);

    // loop over the neighbors if we can add double bonds or
    // simply push them onto the stack
    INT_DEQUE opts;
    bool cCand = false;
    if (dBndCands[curr]) {
      cCand = true;
    }
    int ncnd;
    // if we are here because of backtracking
    if (options.find(curr) != options.end()) {
      opts = options[curr];
      CHECK_INVARIANT(opts.size() > 0, "");
    } else {
      RWMol::ADJ_ITER nbrIdx, endNbrs;
      boost::tie(nbrIdx, endNbrs) =
          mol.getAtomNeighbors(mol.getAtomWithIdx(curr));
      while (nbrIdx != endNbrs) {
        // ignore if the neighbor has already been dealt with before
        if (std::find(done.begin(), done.end(), static_cast<int>(*nbrIdx)) !=
            done.end()) {
          ++nbrIdx;
          continue;
        }
        // ignore if the neighbor is not part of the fused system
        if (std::find(allAtms.begin(), allAtms.end(),
                      static_cast<int>(*nbrIdx)) == allAtms.end()) {
          ++nbrIdx;
          continue;
        }

        // if the neighbor is not on the stack add it
        if (std::find(astack.begin(), astack.end(),
                      static_cast<int>(*nbrIdx)) == astack.end()) {
          astack.push_back(rdcast<int>(*nbrIdx));
        }

        // check if the neighbor is also a candidate for a double bond
        // the refinement that we'll make to the candidate check we've already
        // done is to make sure that the bond is either flagged as aromatic
        // or involves a dummy atom. This was Issue 3525076.
        // This fix is not really 100% of the way there: a situation like
        // that for Issue 3525076 but involving a dummy atom in the cage
        // could lead to the same failure. The full fix would require
        // a fairly detailed analysis of all bonds in the molecule to determine
        // which of them is eligible to be converted.
        if (cCand && dBndCands[*nbrIdx] &&
            (mol.getBondBetweenAtoms(curr, *nbrIdx)->getIsAromatic() ||
             mol.getAtomWithIdx(curr)->getAtomicNum() == 0 ||
             mol.getAtomWithIdx(*nbrIdx)->getAtomicNum() == 0)) {
          opts.push_back(rdcast<int>(*nbrIdx));
        }  // end of curr atoms can have a double bond
        ++nbrIdx;
      }  // end of looping over neighbors
    }
    // now add a double bond from current to one of the neighbors if we can
    if (cCand) {
      if (opts.size() > 0) {
        ncnd = opts.front();
        opts.pop_front();
        Bond *bnd = mol.getBondBetweenAtoms(curr, ncnd);
        bnd->setBondType(Bond::DOUBLE);

        // remove current and the neighbor from the dBndCands list
        dBndCands[curr] = 0;
        dBndCands[ncnd] = 0;

        // add them to the list of bonds to which have been made double
        dBndAdds[bnd->getIdx()] = 1;
        localBondsAdded[bnd->getIdx()] = 1;

        // if this is an atom we previously visted and picked we
        // simply tried a different option now, overwrite the options
        // stored for this atoms
        if (options.find(curr) != options.end()) {
          if (opts.size() == 0) {
            options.erase(curr);
            btmoves.pop_back();
            if (btmoves.size() > 0) {
              lastOpt = btmoves.back();
            } else {
              lastOpt = -1;
            }
          } else {
            options[curr] = opts;
          }
        } else {
          // this is new atoms we are trying and have other
          // neighbors as options to add double bond store this to
          // the options stack, we may have made a mistake in
          // which one we chose and have to return here
          if (opts.size() > 0) {
            lastOpt = curr;
            btmoves.push_back(lastOpt);
            options[curr] = opts;
          }
        }

      }  // end of adding a double bond
      else {
        // we have an atom that should be getting a double bond
        // but none of the neighbors can take one. Most likely
        // because of a wrong choice earlier so back track
        if ((lastOpt >= 0) && (numBT < maxBackTracks)) {
          // std::cerr << "PRE BACKTRACK" << std::endl;
          // mol.debugMol(std::cerr);
          backTrack(mol, options, lastOpt, done, astack, dBndCands, dBndAdds);
          // std::cerr << "POST BACKTRACK" << std::endl;
          // mol.debugMol(std::cerr);
          numBT++;
        } else {
          // undo any remaining changes we made while here
          // this was github #962
          for (unsigned int bidx = 0; bidx < mol.getNumBonds(); ++bidx) {
            if (localBondsAdded[bidx]) {
              mol.getBondWithIdx(bidx)->setBondType(Bond::SINGLE);
            }
          }
          return false;
        }
      }  // end of else try to backtrack
    }    // end of curr atom atom being a cand for double bond
  }      // end of while we are not done with all atoms
  return true;
}
Beispiel #27
0
int main(){
  RDLog::InitLogs();
  Dict d;
  INT_VECT fooV;
  fooV.resize(3);
  BOOST_LOG(rdInfoLog) << "dict test" << std::endl;
  CHECK_INVARIANT(!d.hasVal("foo"),"bad init");
  int x = 1;
  d.setVal("foo", x);
  CHECK_INVARIANT(d.hasVal("foo"),"should be there");
  CHECK_INVARIANT(!d.hasVal("bar"),"bad other key");
  int v,v2;
  d.getVal("foo",v);
  CHECK_INVARIANT(v==1,"bad val");
  v2=d.getVal<int>("foo");
  CHECK_INVARIANT(v2==v,"bad val");
  d.setVal("bar",fooV);
  d.getVal("foo",v);
  CHECK_INVARIANT(v==1,"bad val");
  v2=d.getVal<int>("foo");
  CHECK_INVARIANT(v2==v,"bad val");
  INT_VECT fooV2,fooV3;
  d.getVal("bar",fooV2);
  fooV3=d.getVal<INT_VECT>("bar");
  CHECK_INVARIANT(fooV==fooV2,"bad getVal");
  CHECK_INVARIANT(fooV2==fooV3,"bad getVal");
  

  VECT_INT_VECT fooV4;
  fooV4.resize(3);
  CHECK_INVARIANT(!d.hasVal("baz"),"bad get");
  d.setVal("baz",fooV4);
  CHECK_INVARIANT(d.hasVal("baz"),"bad get");

  DictCon dc1;
  CHECK_INVARIANT(!dc1.getDict()->hasVal("foo"),"bad init");
  int y = 1;
  dc1.getDict()->setVal("foo",y);
  CHECK_INVARIANT(dc1.getDict()->hasVal("foo"),"should be there");
  CHECK_INVARIANT(!dc1.getDict()->hasVal("bar"),"bad other key");
  dc1.getDict()->setVal("bar",fooV);
  dc1.getDict()->getVal("foo",v);
  CHECK_INVARIANT(v==1,"bad val");
  dc1.getDict()->getVal("bar",fooV2);
  CHECK_INVARIANT(fooV==fooV2,"bad getVal");
  fooV4.resize(3);
  CHECK_INVARIANT(!dc1.getDict()->hasVal("baz"),"bad get");
  dc1.getDict()->setVal("baz",fooV4);
  CHECK_INVARIANT(dc1.getDict()->hasVal("baz"),"bad get");

  dc1.getDict()->reset();

  DictCon dc2=dc1;
  CHECK_INVARIANT(!dc2.getDict()->hasVal("foo"),"bad init");
  int z = 1;
  dc2.getDict()->setVal("foo",z);
  CHECK_INVARIANT(dc2.getDict()->hasVal("foo"),"should be there");
  CHECK_INVARIANT(!dc2.getDict()->hasVal("bar"),"bad other key");
  dc2.getDict()->setVal("bar",fooV);
  dc2.getDict()->getVal("foo",v);
  CHECK_INVARIANT(v==1,"bad val");
  dc2.getDict()->getVal("bar",fooV2);
  CHECK_INVARIANT(fooV==fooV2,"bad getVal");
  fooV4.resize(3);
  CHECK_INVARIANT(!dc2.getDict()->hasVal("baz"),"bad get");
  dc2.getDict()->setVal("baz",fooV4);
  CHECK_INVARIANT(dc2.getDict()->hasVal("baz"),"bad get");

  DictCon dc3(dc2);
  CHECK_INVARIANT(dc3.getDict()->hasVal("foo"),"should be there");
  dc3.getDict()->getVal("foo",v);
  CHECK_INVARIANT(v==1,"bad val");
  dc3.getDict()->getVal("bar",fooV2);
  CHECK_INVARIANT(fooV==fooV2,"bad getVal");
  fooV4.resize(3);
  CHECK_INVARIANT(dc3.getDict()->hasVal("baz"),"bad get");

  CHECK_INVARIANT(dc3.getDict()->hasVal("foo"),"should be there");
  dc3.getDict()->getVal("foo",v);
  CHECK_INVARIANT(v==1,"bad val");
  dc3.getDict()->getVal("bar",fooV2);
  CHECK_INVARIANT(fooV==fooV2,"bad getVal");
  fooV4.resize(3);
  CHECK_INVARIANT(dc3.getDict()->hasVal("baz"),"bad get");
  
  testStringVals();
  testVectToString();

  return 0;

}