19#include <boost/dynamic_bitset.hpp>
35 unsigned int bondStereo{
36 static_cast<unsigned int>(Bond::BondStereo::STEREONONE)};
37 unsigned int nbrSymClass{0};
38 unsigned int nbrIdx{0};
40 const canon_atom *controllingAtoms[4]{
nullptr,
nullptr,
nullptr,
nullptr};
41 const std::string *p_symbol{
43 unsigned int bondIdx{0};
47 unsigned int nsc,
unsigned int bidx)
49 bondStereo(static_cast<unsigned int>(bs)),
54 unsigned int nsc,
unsigned int bidx)
65 return compare(lhs, rhs) > 0;
69 unsigned int div = 1) {
103 unsigned int degree{0};
104 unsigned int totalNumHs{0};
105 bool hasRingNbr{
false};
106 bool isRingStereoAtom{
false};
107 unsigned int whichStereoGroup{0};
110 const std::string *p_symbol{
122 std::vector<std::pair<unsigned int, unsigned int>> &
result);
139 const boost::dynamic_bitset<> *dp_atomsInPlay{
nullptr},
140 *dp_bondsInPlay{
nullptr};
145 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
146 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
149 dp_atomsInPlay(atomsInPlay),
150 dp_bondsInPlay(bondsInPlay) {}
155 if (dp_atomsInPlay && !((*dp_atomsInPlay)[i] || (*dp_atomsInPlay)[j])) {
159 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
162 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
165 for (
unsigned int ii = 0;
166 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size(); ++ii) {
168 bondholder::compare(dp_atoms[i].bonds[ii], dp_atoms[j].bonds[ii]);
174 std::vector<std::pair<unsigned int, unsigned int>> swapsi;
175 std::vector<std::pair<unsigned int, unsigned int>> swapsj;
176 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
179 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
182 for (
unsigned int ii = 0; ii < swapsi.size() && ii < swapsj.size(); ++ii) {
183 int cmp = swapsi[ii].second - swapsj[ii].second;
196 const boost::dynamic_bitset<> *dp_atomsInPlay{
nullptr},
197 *dp_bondsInPlay{
nullptr};
202 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
203 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
206 dp_atomsInPlay(atomsInPlay),
207 dp_bondsInPlay(bondsInPlay) {}
212 if (dp_atomsInPlay && !((*dp_atomsInPlay)[i] || (*dp_atomsInPlay)[j])) {
216 if (dp_atoms[i].neighborNum < dp_atoms[j].neighborNum) {
218 }
else if (dp_atoms[i].neighborNum > dp_atoms[j].neighborNum) {
222 if (dp_atoms[i].revistedNeighbors < dp_atoms[j].revistedNeighbors) {
224 }
else if (dp_atoms[i].revistedNeighbors > dp_atoms[j].revistedNeighbors) {
228 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
231 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
234 for (
unsigned int ii = 0;
235 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size(); ++ii) {
237 bondholder::compare(dp_atoms[i].bonds[ii], dp_atoms[j].bonds[ii]);
243 if (dp_atoms[i].bonds.size() < dp_atoms[j].bonds.size()) {
245 }
else if (dp_atoms[i].bonds.size() > dp_atoms[j].bonds.size()) {
255 unsigned int res = 0;
256 std::vector<unsigned int>
perm;
257 perm.reserve(dp_atoms[i].atom->getDegree());
258 for (
const auto nbr : dp_mol->atomNeighbors(dp_atoms[i].atom)) {
259 auto rnk = dp_atoms[
nbr->getIdx()].index;
267 if (
perm.size() == dp_atoms[i].atom->getDegree()) {
268 auto ctag = dp_atoms[i].atom->getChiralTag();
284 unsigned int getAtomRingNbrCode(
unsigned int i)
const {
285 if (!dp_atoms[i].hasRingNbr) {
289 auto nbrs = dp_atoms[i].nbrIds.get();
290 unsigned int code = 0;
291 for (
unsigned j = 0; j < dp_atoms[i].degree; ++j) {
292 if (dp_atoms[nbrs[j]].isRingStereoAtom) {
293 code += dp_atoms[nbrs[j]].index * 10000 + 1;
299 int basecomp(
int i,
int j)
const {
300 unsigned int ivi, ivj;
303 ivi = dp_atoms[i].index;
304 ivj = dp_atoms[j].index;
307 }
else if (ivi > ivj) {
311 if (df_useNonStereoRanks) {
313 int rankingNumber_i = 0;
314 int rankingNumber_j = 0;
315 dp_atoms[i].atom->getPropIfPresent(
316 common_properties::_CanonicalRankingNumber, rankingNumber_i);
317 dp_atoms[j].atom->getPropIfPresent(
318 common_properties::_CanonicalRankingNumber, rankingNumber_j);
319 if (rankingNumber_i < rankingNumber_j) {
321 }
else if (rankingNumber_i > rankingNumber_j) {
326 if (df_useAtomMaps || df_useAtomMapsOnDummies) {
328 int molAtomMapNumber_i = 0;
329 int molAtomMapNumber_j = 0;
330 if (df_useAtomMaps ||
331 (df_useAtomMapsOnDummies && dp_atoms[i].atom->getAtomicNum() == 0)) {
332 dp_atoms[i].atom->getPropIfPresent(common_properties::molAtomMapNumber,
335 if (df_useAtomMaps ||
336 (df_useAtomMapsOnDummies && dp_atoms[j].atom->getAtomicNum() == 0)) {
337 dp_atoms[j].atom->getPropIfPresent(common_properties::molAtomMapNumber,
340 if (molAtomMapNumber_i < molAtomMapNumber_j) {
342 }
else if (molAtomMapNumber_i > molAtomMapNumber_j) {
347 ivi = dp_atoms[i].degree;
348 ivj = dp_atoms[j].degree;
351 }
else if (ivi > ivj) {
354 if (dp_atoms[i].p_symbol && dp_atoms[j].p_symbol) {
355 if (*(dp_atoms[i].p_symbol) < *(dp_atoms[j].p_symbol)) {
357 }
else if (*(dp_atoms[i].p_symbol) > *(dp_atoms[j].p_symbol)) {
365 ivi = dp_atoms[i].atom->getAtomicNum();
366 ivj = dp_atoms[j].atom->getAtomicNum();
369 }
else if (ivi > ivj) {
373 if (df_useIsotopes) {
374 ivi = dp_atoms[i].atom->getIsotope();
375 ivj = dp_atoms[j].atom->getIsotope();
378 }
else if (ivi > ivj) {
384 ivi = dp_atoms[i].totalNumHs;
385 ivj = dp_atoms[j].totalNumHs;
388 }
else if (ivi > ivj) {
392 ivi = dp_atoms[i].atom->getFormalCharge();
393 ivj = dp_atoms[j].atom->getFormalCharge();
396 }
else if (ivi > ivj) {
400 if (df_useChiralPresence) {
402 dp_atoms[i].atom->getChiralTag() != Atom::ChiralType::CHI_UNSPECIFIED;
404 dp_atoms[j].atom->getChiralTag() != Atom::ChiralType::CHI_UNSPECIFIED;
407 }
else if (ivi > ivj) {
412 if (df_useChirality) {
414 ivi = dp_atoms[i].whichStereoGroup;
416 ivj = dp_atoms[j].whichStereoGroup;
420 }
else if (ivj && !ivi) {
422 }
else if (ivi && ivj) {
423 auto iType = dp_atoms[i].typeOfStereoGroup;
424 auto jType = dp_atoms[j].typeOfStereoGroup;
427 }
else if (iType > jType) {
432 std::set<unsigned int> sgi;
433 for (
const auto sgat :
435 sgi.insert(dp_atoms[sgat->getIdx()].index);
437 std::set<unsigned int> sgj;
438 for (
const auto sgat :
440 sgj.insert(dp_atoms[sgat->getIdx()].index);
444 }
else if (sgi > sgj) {
448 if (iType == StereoGroupType::STEREO_ABSOLUTE) {
449 ivi = getChiralRank(dp_mol, dp_atoms, i);
450 ivj = getChiralRank(dp_mol, dp_atoms, j);
453 }
else if (ivi > ivj) {
465 ivi = dp_atoms[i].atom->getChiralTag() != 0;
466 ivj = dp_atoms[j].atom->getChiralTag() != 0;
469 }
else if (ivi > ivj) {
475 ivi = getChiralRank(dp_mol, dp_atoms, i);
478 ivj = getChiralRank(dp_mol, dp_atoms, j);
482 }
else if (ivi > ivj) {
489 if (df_useChiralityRings) {
491 ivi = getAtomRingNbrCode(i);
492 ivj = getAtomRingNbrCode(j);
495 }
else if (ivi > ivj) {
505 const boost::dynamic_bitset<> *dp_atomsInPlay{
nullptr},
506 *dp_bondsInPlay{
nullptr};
507 bool df_useNbrs{
false};
508 bool df_useIsotopes{
true};
509 bool df_useChirality{
true};
510 bool df_useChiralityRings{
true};
511 bool df_useAtomMaps{
true};
512 bool df_useNonStereoRanks{
false};
513 bool df_useChiralPresence{
true};
514 bool df_useAtomMapsOnDummies{
true};
518 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
519 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
522 dp_atomsInPlay(atomsInPlay),
523 dp_bondsInPlay(bondsInPlay) {}
526 if (dp_atomsInPlay && !((*dp_atomsInPlay)[i] || (*dp_atomsInPlay)[j])) {
529 int v = basecomp(i, j);
535 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
538 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
542 for (
unsigned int ii = 0;
543 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
546 bondholder::compare(dp_atoms[i].bonds[ii], dp_atoms[j].bonds[ii]);
552 if (dp_atoms[i].bonds.size() < dp_atoms[j].bonds.size()) {
554 }
else if (dp_atoms[i].bonds.size() > dp_atoms[j].bonds.size()) {
569 void getAtomNeighborhood(std::vector<bondholder> &nbrs)
const {
570 for (
unsigned j = 0; j < nbrs.size(); ++j) {
571 unsigned int nbrIdx = nbrs[j].nbrIdx;
576 const Atom *nbr = dp_atoms[nbrIdx].atom;
577 nbrs[j].nbrSymClass =
580 std::sort(nbrs.begin(), nbrs.end(), bondholder::greater);
584 int basecomp(
int i,
int j)
const {
586 unsigned int ivi, ivj;
589 ivi = dp_atoms[i].index;
590 ivj = dp_atoms[j].index;
593 }
else if (ivi > ivj) {
598 ivi = dp_atoms[i].atom->getAtomicNum();
599 ivj = dp_atoms[j].atom->getAtomicNum();
602 }
else if (ivi > ivj) {
607 ivi = dp_atoms[i].atom->getIsotope();
608 ivj = dp_atoms[j].atom->getIsotope();
611 }
else if (ivi > ivj) {
619 if (dp_atoms[i].atom->getPropIfPresent(common_properties::_CIPCode,
621 ivi = cipCode ==
"R" ? 2 : 1;
623 if (dp_atoms[j].atom->getPropIfPresent(common_properties::_CIPCode,
625 ivj = cipCode ==
"R" ? 2 : 1;
629 }
else if (ivi > ivj) {
640 bool df_useNbrs{
false};
643 : dp_atoms(atoms), dp_mol(&m), df_useNbrs(false) {}
648 int v = basecomp(i, j);
654 getAtomNeighborhood(dp_atoms[i].bonds);
655 getAtomNeighborhood(dp_atoms[j].bonds);
660 for (
unsigned int ii = 0;
661 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
663 int cmp = bondholder::compare(
669 for (
unsigned int ii = 0;
670 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
673 bondholder::compare(dp_atoms[i].bonds[ii], dp_atoms[j].bonds[ii]);
678 if (dp_atoms[i].bonds.size() < dp_atoms[j].bonds.size()) {
680 }
else if (dp_atoms[i].bonds.size() > dp_atoms[j].bonds.size()) {
693template <
typename CompareFunc>
726 start = order + offset;
744 for (
int k = 0;
k <
len; ++
k) {
751 for (i =
count[index]; i <
len; i++) {
761 for (
unsigned j = 0;
j < atoms[index].
degree; ++
j) {
769 for (i =
count[index]; i <
len; i++) {
771 for (
unsigned j = 0;
j < atoms[index].
degree; ++
j) {
790template <
typename CompareFunc>
801 for (
unsigned int i = 0; i <
nAtoms; i++) {
807 index = order[offset];
808 atoms[index].
index = offset;
813 if (atoms[index].degree < 1) {
816 for (
unsigned j = 0;
j < atoms[index].
degree; ++
j) {
843 int *order,
int *
count,
852 const ROMol &mol, std::vector<unsigned int> &
res,
bool breakTies =
true,
859 const ROMol &mol, std::vector<unsigned int> &
res,
862 const std::vector<std::string> *atomSymbols,
863 const std::vector<std::string> *
bondSymbols,
bool breakTies,
869 const ROMol &mol, std::vector<unsigned int> &
res,
872 const std::vector<std::string> *atomSymbols =
nullptr,
882 std::vector<unsigned int> &
res);
885 std::vector<Canon::canon_atom> &atoms,
891 std::vector<Canon::canon_atom> &atoms,
893 const std::vector<std::string> *atomSymbols,
900 bool useSpecial =
false,
bool useChirality =
false,
901 const boost::dynamic_bitset<> *
atomsInPlay =
nullptr,
902 const boost::dynamic_bitset<> *
bondsInPlay =
nullptr);
#define PRECONDITION(expr, mess)
Defines the primary molecule class ROMol as well as associated typedefs.
Defines the class StereoGroup which stores relationships between the absolute configurations of atoms...
The class for representing atoms.
int getAtomicNum() const
returns our atomic number
@ CHI_TETRAHEDRAL_CW
tetrahedral: clockwise rotation (SMILES @@)
@ CHI_TETRAHEDRAL_CCW
tetrahedral: counter-clockwise rotation (SMILES
BondStereo
the nature of the bond's stereochem (for cis/trans)
AtomCompareFunctor(Canon::canon_atom *atoms, const ROMol &m, const boost::dynamic_bitset<> *atomsInPlay=nullptr, const boost::dynamic_bitset<> *bondsInPlay=nullptr)
int operator()(int i, int j) const
ChiralAtomCompareFunctor(Canon::canon_atom *atoms, const ROMol &m)
int operator()(int i, int j) const
ChiralAtomCompareFunctor()
int operator()(int i, int j) const
SpecialChiralityAtomCompareFunctor(Canon::canon_atom *atoms, const ROMol &m, const boost::dynamic_bitset<> *atomsInPlay=nullptr, const boost::dynamic_bitset<> *bondsInPlay=nullptr)
SpecialChiralityAtomCompareFunctor()
SpecialSymmetryAtomCompareFunctor()
SpecialSymmetryAtomCompareFunctor(Canon::canon_atom *atoms, const ROMol &m, const boost::dynamic_bitset<> *atomsInPlay=nullptr, const boost::dynamic_bitset<> *bondsInPlay=nullptr)
int operator()(int i, int j) const
const std::vector< StereoGroup > & getStereoGroups() const
Gets a reference to the groups of atoms with relative stereochemistry.
unsigned int getNumAtoms() const
returns our number of atoms
#define RDKIT_GRAPHMOL_EXPORT
void rankWithFunctor(T &ftor, bool breakTies, int *order, bool useSpecial=false, bool useChirality=false, const boost::dynamic_bitset<> *atomsInPlay=nullptr, const boost::dynamic_bitset<> *bondsInPlay=nullptr)
void initFragmentCanonAtoms(const ROMol &mol, std::vector< Canon::canon_atom > &atoms, bool includeChirality, const std::vector< std::string > *atomSymbols, const std::vector< std::string > *bondSymbols, const boost::dynamic_bitset<> &atomsInPlay, const boost::dynamic_bitset<> &bondsInPlay, bool needsInit)
RDKIT_GRAPHMOL_EXPORT void initCanonAtoms(const ROMol &mol, std::vector< Canon::canon_atom > &atoms, bool includeChirality=true, bool includeStereoGroups=true)
RDKIT_GRAPHMOL_EXPORT void CreateSinglePartition(unsigned int nAtoms, int *order, int *count, canon_atom *atoms)
RDKIT_GRAPHMOL_EXPORT void rankFragmentAtoms(const ROMol &mol, std::vector< unsigned int > &res, const boost::dynamic_bitset<> &atomsInPlay, const boost::dynamic_bitset<> &bondsInPlay, const std::vector< std::string > *atomSymbols, const std::vector< std::string > *bondSymbols, bool breakTies, bool includeChirality, bool includeIsotope, bool includeAtomMaps, bool includeChiralPresence)
Note that atom maps on dummy atoms will always be used.
RDKIT_GRAPHMOL_EXPORT void ActivatePartitions(unsigned int nAtoms, int *order, int *count, int &activeset, int *next, int *changed)
const unsigned int ATNUM_CLASS_OFFSET
RDKIT_GRAPHMOL_EXPORT void updateAtomNeighborNumSwaps(canon_atom *atoms, std::vector< bondholder > &nbrs, unsigned int atomIdx, std::vector< std::pair< unsigned int, unsigned int > > &result)
void BreakTies(const ROMol &mol, canon_atom *atoms, CompareFunc compar, int mode, int *order, int *count, int &activeset, int *next, int *changed, char *touchedPartitions)
RDKIT_GRAPHMOL_EXPORT void rankMolAtoms(const ROMol &mol, std::vector< unsigned int > &res, bool breakTies=true, bool includeChirality=true, bool includeIsotopes=true, bool includeAtomMaps=true, bool includeChiralPresence=false, bool includeStereoGroups=true, bool useNonStereoRanks=false)
Note that atom maps on dummy atoms will always be used.
void RefinePartitions(const ROMol &mol, canon_atom *atoms, CompareFunc compar, int mode, int *order, int *count, int &activeset, int *next, int *changed, char *touchedPartitions)
RDKIT_GRAPHMOL_EXPORT void chiralRankMolAtoms(const ROMol &mol, std::vector< unsigned int > &res)
RDKIT_GRAPHMOL_EXPORT void updateAtomNeighborIndex(canon_atom *atoms, std::vector< bondholder > &nbrs)
bool rdvalue_is(const RDValue_cast_t)
void hanoisort(int *base, int nel, int *count, int *changed, CompareFunc compar)
unsigned int countSwapsToInterconvert(const T &ref, T probe)
const std::string * p_symbol
static bool greater(const bondholder &lhs, const bondholder &rhs)
bool operator<(const bondholder &o) const
int compareStereo(const bondholder &o) const
bondholder(Bond::BondType bt, unsigned int bs, unsigned int ni, unsigned int nsc, unsigned int bidx)
bondholder(Bond::BondType bt, Bond::BondStereo bs, unsigned int ni, unsigned int nsc, unsigned int bidx)
static int compare(const bondholder &x, const bondholder &y, unsigned int div=1)
std::vector< bondholder > bonds
std::unique_ptr< int[]> nbrIds
std::vector< int > revistedNeighbors
std::vector< int > neighborNum