/** * This function finds the LSSR containing all relevant cycles. A cycle is * relevant if it belongs to at least one minimum cycle basis. Another * description is more useful though: * * A cycle (C) is relevant if: * - no smaller cycles C_i, ..., C_k exist such that C = C_1 + ... + C_k * - both bonds & atoms are checked * * This is based on lemma 1 from: * * P. Vismara, Union of all the minimum cycle bases of a graph, The electronic * journal of combinatorics, Vol. 4, 1997 * http://www.emis.de/journals/EJC/Volume_4/PostScriptfiles/v4i1r9.ps */ void visitRing(OBMol *mol, OBRing *ring, std::vector<OBRing*> &rlist, std::vector<OBRing*> &rignored) { const std::vector<int> &atoms = ring->_path; OBBitVec mask; // Make sure mask is the same size as the maximum ring atom/bond index. mask.SetBitOn(mol->NumAtoms()); mask.SetBitOn(mol->NumBonds()); // // Remove larger rings that cover the same atoms as smaller rings. // mask.Clear(); for (unsigned int j = 0; j < rlist.size(); ++j) // Here we select only smaller rings. if (rlist[j]->_path.size() < ring->_path.size()) mask |= rlist[j]->_pathset; mask = mask & ring->_pathset; bool containsSmallerAtomRing = (mask == ring->_pathset) ? true : false; // Translate ring atom indexes to ring bond indexes. std::vector<unsigned int> bonds = atomRingToBondRing(mol, ring->_path); OBBitVec bondset; for (unsigned int i = 0; i < bonds.size(); ++i) bondset.SetBitOn(bonds[i]); // // Remove larger rings that cover the same bonds as smaller rings. // mask.Clear(); for (unsigned int j = 0; j < rlist.size(); ++j) { std::vector<unsigned int> otherBonds = atomRingToBondRing(mol, rlist[j]->_path); OBBitVec bs; for (unsigned int i = 0; i < otherBonds.size(); ++i) bs.SetBitOn(otherBonds[i]); // Here we select only smaller rings. if (otherBonds.size() < bonds.size()) mask |= bs; } mask = mask & bondset; bool containsSmallerBondRing = (mask == bondset) ? true : false; // The ring is part of the LSSR if all it's atoms and bonds are not // found in smaller rings. if (!containsSmallerAtomRing || !containsSmallerBondRing) { rlist.push_back(ring); } else { rignored.push_back(ring); } }
static int DetermineFRJ(OBMol &mol) { vector<vector<int> >::iterator i; vector<vector<int> > cfl; //find all continuous graphs in the mol area mol.ContigFragList(cfl); if (cfl.empty()) return(0); if (cfl.size() == 1) return(mol.NumBonds() - mol.NumAtoms() + 1); //count up the atoms and bonds belonging to each graph OBBond *bond; vector<OBBond*>::iterator j; int numatoms,numbonds,frj=0; OBBitVec frag; for (i = cfl.begin();i != cfl.end();++i) { frag.Clear(); frag.FromVecInt(*i); numatoms = (*i).size(); numbonds=0; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) if (frag.BitIsOn(bond->GetBeginAtomIdx()) && frag.BitIsOn(bond->GetEndAtomIdx())) numbonds++; frj += numbonds - numatoms + 1; } return(frj); }
void OBRingSearch::RemoveRedundant(int frj) { int i,j; //remove identical rings for (i = _rlist.size()-1;i > 0;i--) for (j = i-1;j >= 0;j--) if ((_rlist[i])->_pathset == (_rlist[j])->_pathset) { delete _rlist[i]; _rlist.erase(_rlist.begin()+i); break; } if (_rlist.size() == 0) return; // nothing to do // handle LSSR if (frj < 0) { OBMol *mol = _rlist[0]->GetParent(); std::vector<OBRing*> rlist, rignored; for (unsigned int i = 0; i < _rlist.size(); ++i) { visitRing(mol, _rlist[i], rlist, rignored); } for (unsigned int i = 0; i < rignored.size(); ++i) delete rignored[i]; _rlist = rlist; return; } // exit if we already have frj rings if (_rlist.size() == (unsigned)frj) return; //make sure tmp is the same size as the rings OBBitVec tmp; for (j = 0;j < (signed)_rlist.size();++j) tmp = (_rlist[j])->_pathset; //remove larger rings that cover the same atoms as smaller rings for (i = _rlist.size()-1;i >= 0;i--) { tmp.Clear(); for (j = 0;j < (signed)_rlist.size();++j) if ((_rlist[j])->_path.size() <= (_rlist[i])->_path.size() && i != j) tmp |= (_rlist[j])->_pathset; tmp = tmp & (_rlist[i])->_pathset; if (tmp == (_rlist[i])->_pathset) { delete _rlist[i]; _rlist.erase(_rlist.begin()+i); } if (_rlist.size() == (unsigned)frj) break; } }
void testIsomorphismMask() { // read file: 3 6-rings // // /\ /\ /\ // | | | | // \/ \/ \/ // OBMol mol; OBConversion conv; conv.SetInFormat("cml"); std::ifstream ifs(OBTestUtil::GetFilename("isomorphism1.cml").c_str()); OB_REQUIRE( ifs ); conv.Read(&mol, &ifs); OBQuery *query = CompileSmilesQuery("C1CCCCC1"); OBIsomorphismMapper *mapper = OBIsomorphismMapper::GetInstance(query); // no mask OBIsomorphismMapper::Mappings maps; mapper->MapUnique(&mol, maps); cout << maps.size() << endl; OB_ASSERT( maps.size() == 3 ); // mask first ring OBBitVec mask; for (int i = 0; i < 6; ++i) mask.SetBitOn(i+1); mapper->MapUnique(&mol, maps, mask); cout << maps.size() << endl; OB_ASSERT( maps.size() == 1 ); // mask second ring also for (int i = 6; i < 10; ++i) mask.SetBitOn(i+1); mapper->MapUnique(&mol, maps, mask); cout << maps.size() << endl; OB_ASSERT( maps.size() == 2 ); // just mask last ring (atomIds 7-8, 10-13) mask.Clear(); for (int i = 10; i < 14; ++i) mask.SetBitOn(i+1); mask.SetBitOn(7 + 1); mask.SetBitOn(8 + 1); mapper->MapUnique(&mol, maps, mask); cout << maps.size() << endl; OB_ASSERT( maps.size() == 1 ); // Should be same result as masking just the first ring delete query; delete mapper; }
void OBRingSearch::RemoveRedundant(int frj) { OBBitVec tmp; int i,j; //remove identical rings for (i = _rlist.size()-1;i > 0;i--) for (j = i-1;j >= 0;j--) if ((_rlist[i])->_pathset == (_rlist[j])->_pathset) { delete _rlist[i]; _rlist.erase(_rlist.begin()+i); break; } //make sure tmp is the same size as the rings for (j = 0;j < (signed)_rlist.size();++j) tmp = (_rlist[j])->_pathset; //remove larger rings that cover the same atoms as smaller rings for (i = _rlist.size()-1;i >= 0;i--) { tmp.Clear(); for (j = 0;j < (signed)_rlist.size();++j) if ((_rlist[j])->_path.size() <= (_rlist[i])->_path.size() && i != j) tmp |= (_rlist[j])->_pathset; tmp = tmp & (_rlist[i])->_pathset; if (tmp == (_rlist[i])->_pathset) { delete _rlist[i]; _rlist.erase(_rlist.begin()+i); } if (_rlist.size() == (unsigned)frj) break; } }