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};
109 int *nbrIds{
nullptr};
110 const std::string *p_symbol{
122 canon_atom *atoms, std::vector<bondholder> &nbrs);
125 canon_atom *atoms, std::vector<bondholder> &nbrs,
unsigned int atomIdx,
126 std::vector<std::pair<unsigned int, unsigned int>> &result);
143 const boost::dynamic_bitset<> *dp_atomsInPlay{
nullptr},
144 *dp_bondsInPlay{
nullptr};
149 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
150 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
153 dp_atomsInPlay(atomsInPlay),
154 dp_bondsInPlay(bondsInPlay) {}
159 if (dp_atomsInPlay && !((*dp_atomsInPlay)[i] || (*dp_atomsInPlay)[j])) {
163 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
166 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
169 for (
unsigned int ii = 0;
170 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size(); ++ii) {
178 std::vector<std::pair<unsigned int, unsigned int>> swapsi;
179 std::vector<std::pair<unsigned int, unsigned int>> swapsj;
180 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
183 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
186 for (
unsigned int ii = 0; ii < swapsi.size() && ii < swapsj.size(); ++ii) {
187 int cmp = swapsi[ii].second - swapsj[ii].second;
200 const boost::dynamic_bitset<> *dp_atomsInPlay{
nullptr},
201 *dp_bondsInPlay{
nullptr};
206 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
207 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
210 dp_atomsInPlay(atomsInPlay),
211 dp_bondsInPlay(bondsInPlay) {}
216 if (dp_atomsInPlay && !((*dp_atomsInPlay)[i] || (*dp_atomsInPlay)[j])) {
220 if (dp_atoms[i].neighborNum < dp_atoms[j].neighborNum) {
222 }
else if (dp_atoms[i].neighborNum > dp_atoms[j].neighborNum) {
226 if (dp_atoms[i].revistedNeighbors < dp_atoms[j].revistedNeighbors) {
228 }
else if (dp_atoms[i].revistedNeighbors > dp_atoms[j].revistedNeighbors) {
232 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
235 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
238 for (
unsigned int ii = 0;
239 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size(); ++ii) {
247 if (dp_atoms[i].bonds.size() < dp_atoms[j].bonds.size()) {
249 }
else if (dp_atoms[i].bonds.size() > dp_atoms[j].bonds.size()) {
257unsigned int getChiralRank(
const ROMol *dp_mol, canon_atom *dp_atoms,
259 unsigned int res = 0;
260 std::vector<unsigned int> perm;
261 perm.reserve(dp_atoms[i].atom->getDegree());
262 for (
const auto nbr : dp_mol->
atomNeighbors(dp_atoms[i].atom)) {
263 auto rnk = dp_atoms[nbr->getIdx()].index;
265 if (std::find(perm.begin(), perm.end(), rnk) != perm.end()) {
271 if (perm.size() == dp_atoms[i].atom->getDegree()) {
272 auto ctag = dp_atoms[i].atom->getChiralTag();
273 if (ctag == Atom::ChiralType::CHI_TETRAHEDRAL_CW ||
274 ctag == Atom::ChiralType::CHI_TETRAHEDRAL_CCW) {
275 auto sortedPerm = perm;
276 std::sort(sortedPerm.begin(), sortedPerm.end());
278 res = ctag == Atom::ChiralType::CHI_TETRAHEDRAL_CW ? 2 : 1;
280 res = res == 2 ? 1 : 2;
288 unsigned int getAtomRingNbrCode(
unsigned int i)
const {
289 if (!dp_atoms[i].hasRingNbr) {
293 int *nbrs = dp_atoms[i].nbrIds;
294 unsigned int code = 0;
295 for (
unsigned j = 0; j < dp_atoms[i].degree; ++j) {
296 if (dp_atoms[nbrs[j]].isRingStereoAtom) {
297 code += dp_atoms[nbrs[j]].index * 10000 + 1;
303 int basecomp(
int i,
int j)
const {
304 unsigned int ivi, ivj;
307 ivi = dp_atoms[i].index;
308 ivj = dp_atoms[j].index;
311 }
else if (ivi > ivj) {
319 int molAtomMapNumber_i = 0;
320 int molAtomMapNumber_j = 0;
325 if (molAtomMapNumber_i < molAtomMapNumber_j) {
327 }
else if (molAtomMapNumber_i > molAtomMapNumber_j) {
331 ivi = dp_atoms[i].degree;
332 ivj = dp_atoms[j].degree;
335 }
else if (ivi > ivj) {
338 if (dp_atoms[i].p_symbol && dp_atoms[j].p_symbol) {
339 if (*(dp_atoms[i].p_symbol) < *(dp_atoms[j].p_symbol)) {
341 }
else if (*(dp_atoms[i].p_symbol) > *(dp_atoms[j].p_symbol)) {
349 ivi = dp_atoms[i].atom->getAtomicNum();
350 ivj = dp_atoms[j].atom->getAtomicNum();
353 }
else if (ivi > ivj) {
357 if (df_useIsotopes) {
358 ivi = dp_atoms[i].atom->getIsotope();
359 ivj = dp_atoms[j].atom->getIsotope();
362 }
else if (ivi > ivj) {
368 ivi = dp_atoms[i].totalNumHs;
369 ivj = dp_atoms[j].totalNumHs;
372 }
else if (ivi > ivj) {
376 ivi = dp_atoms[i].atom->getFormalCharge();
377 ivj = dp_atoms[j].atom->getFormalCharge();
380 }
else if (ivi > ivj) {
384 if (df_useChirality) {
386 ivi = dp_atoms[i].whichStereoGroup;
388 ivj = dp_atoms[j].whichStereoGroup;
392 }
else if (ivj && !ivi) {
394 }
else if (ivi && ivj) {
395 ivi =
static_cast<unsigned int>(dp_atoms[i].typeOfStereoGroup);
396 ivj =
static_cast<unsigned int>(dp_atoms[j].typeOfStereoGroup);
399 }
else if (ivi > ivj) {
402 ivi = dp_atoms[i].whichStereoGroup - 1;
403 ivj = dp_atoms[j].whichStereoGroup - 1;
405 std::set<unsigned int> sgi;
407 sgi.insert(dp_atoms[sgat->getIdx()].index);
409 std::set<unsigned int> sgj;
411 sgj.insert(dp_atoms[sgat->getIdx()].index);
415 }
else if (sgi > sgj) {
425 ivi = dp_atoms[i].atom->getChiralTag() != 0;
426 ivj = dp_atoms[j].atom->getChiralTag() != 0;
429 }
else if (ivi > ivj) {
435 ivi = getChiralRank(dp_mol, dp_atoms, i);
438 ivj = getChiralRank(dp_mol, dp_atoms, j);
442 }
else if (ivi > ivj) {
449 if (df_useChiralityRings) {
451 ivi = getAtomRingNbrCode(i);
452 ivj = getAtomRingNbrCode(j);
455 }
else if (ivi > ivj) {
465 const boost::dynamic_bitset<> *dp_atomsInPlay{
nullptr},
466 *dp_bondsInPlay{
nullptr};
467 bool df_useNbrs{
false};
468 bool df_useIsotopes{
true};
469 bool df_useChirality{
true};
470 bool df_useChiralityRings{
true};
474 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
475 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
478 dp_atomsInPlay(atomsInPlay),
479 dp_bondsInPlay(bondsInPlay),
481 df_useIsotopes(true),
482 df_useChirality(true),
483 df_useChiralityRings(true) {}
485 if (dp_atomsInPlay && !((*dp_atomsInPlay)[i] || (*dp_atomsInPlay)[j])) {
488 int v = basecomp(i, j);
494 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
497 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
501 for (
unsigned int ii = 0;
502 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
511 if (dp_atoms[i].bonds.size() < dp_atoms[j].bonds.size()) {
513 }
else if (dp_atoms[i].bonds.size() > dp_atoms[j].bonds.size()) {
528 void getAtomNeighborhood(std::vector<bondholder> &nbrs)
const {
529 for (
unsigned j = 0; j < nbrs.size(); ++j) {
530 unsigned int nbrIdx = nbrs[j].nbrIdx;
535 const Atom *nbr = dp_atoms[nbrIdx].atom;
536 nbrs[j].nbrSymClass =
543 int basecomp(
int i,
int j)
const {
545 unsigned int ivi, ivj;
548 ivi = dp_atoms[i].index;
549 ivj = dp_atoms[j].index;
552 }
else if (ivi > ivj) {
557 ivi = dp_atoms[i].atom->getAtomicNum();
558 ivj = dp_atoms[j].atom->getAtomicNum();
561 }
else if (ivi > ivj) {
566 ivi = dp_atoms[i].atom->getIsotope();
567 ivj = dp_atoms[j].atom->getIsotope();
570 }
else if (ivi > ivj) {
580 ivi = cipCode ==
"R" ? 2 : 1;
584 ivj = cipCode ==
"R" ? 2 : 1;
588 }
else if (ivi > ivj) {
599 bool df_useNbrs{
false};
602 : dp_atoms(atoms), dp_mol(&m), df_useNbrs(false) {}
607 int v = basecomp(i, j);
613 getAtomNeighborhood(dp_atoms[i].bonds);
614 getAtomNeighborhood(dp_atoms[j].bonds);
619 for (
unsigned int ii = 0;
620 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
628 for (
unsigned int ii = 0;
629 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
637 if (dp_atoms[i].bonds.size() < dp_atoms[j].bonds.size()) {
639 }
else if (dp_atoms[i].bonds.size() > dp_atoms[j].bonds.size()) {
652template <
typename CompareFunc>
654 int mode,
int *order,
int *count,
int &activeset,
655 int *next,
int *changed,
char *touchedPartitions) {
667 while (activeset != -1) {
679 partition = activeset;
680 activeset = next[partition];
681 next[partition] = -2;
683 len = count[partition];
684 offset = atoms[partition].
index;
685 start = order + offset;
696 hanoisort(start, len, count, changed, compar);
703 for (
int k = 0; k < len; ++k) {
704 changed[start[k]] = 0;
710 for (i = count[index]; i < len; i++) {
713 symclass = offset + i;
715 atoms[index].
index = symclass;
720 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
721 changed[atoms[index].
nbrIds[j]] = 1;
728 for (i = count[index]; i < len; i++) {
730 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
731 unsigned int nbor = atoms[index].
nbrIds[j];
732 touchedPartitions[atoms[nbor].
index] = 1;
735 for (
unsigned int ii = 0; ii < nAtoms; ++ii) {
736 if (touchedPartitions[ii]) {
737 partition = order[ii];
738 if ((count[partition] > 1) && (next[partition] == -2)) {
739 next[partition] = activeset;
740 activeset = partition;
742 touchedPartitions[ii] = 0;
749template <
typename CompareFunc>
751 int mode,
int *order,
int *count,
int &activeset,
int *next,
752 int *changed,
char *touchedPartitions) {
760 for (
unsigned int i = 0; i < nAtoms; i++) {
761 partition = order[i];
762 oldPart = atoms[partition].
index;
763 while (count[partition] > 1) {
764 len = count[partition];
765 offset = atoms[partition].
index + len - 1;
766 index = order[offset];
767 atoms[index].
index = offset;
768 count[partition] = len - 1;
772 if (atoms[index].degree < 1) {
775 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
776 unsigned int nbor = atoms[index].
nbrIds[j];
777 touchedPartitions[atoms[nbor].
index] = 1;
781 for (
unsigned int ii = 0; ii < nAtoms; ++ii) {
782 if (touchedPartitions[ii]) {
783 int npart = order[ii];
784 if ((count[npart] > 1) && (next[npart] == -2)) {
785 next[npart] = activeset;
788 touchedPartitions[ii] = 0;
792 changed, touchedPartitions);
795 if (atoms[partition].index != oldPart) {
802 int *order,
int *count,
806 int *count,
int &activeset,
807 int *next,
int *changed);
810 std::vector<unsigned int> &res,
811 bool breakTies =
true,
812 bool includeChirality =
true,
813 bool includeIsotopes =
true);
816 const ROMol &mol, std::vector<unsigned int> &res,
817 const boost::dynamic_bitset<> &atomsInPlay,
818 const boost::dynamic_bitset<> &bondsInPlay,
819 const std::vector<std::string> *atomSymbols,
820 const std::vector<std::string> *bondSymbols,
bool breakTies,
821 bool includeChirality,
bool includeIsotope);
824 const ROMol &mol, std::vector<unsigned int> &res,
825 const boost::dynamic_bitset<> &atomsInPlay,
826 const boost::dynamic_bitset<> &bondsInPlay,
827 const std::vector<std::string> *atomSymbols =
nullptr,
828 bool breakTies =
true,
bool includeChirality =
true,
829 bool includeIsotopes =
true) {
831 breakTies, includeChirality, includeIsotopes);
835 std::vector<unsigned int> &res);
838 std::vector<Canon::canon_atom> &atoms,
839 bool includeChirality =
true);
843 std::vector<Canon::canon_atom> &atoms,
844 bool includeChirality,
845 const std::vector<std::string> *atomSymbols,
846 const std::vector<std::string> *bondSymbols,
847 const boost::dynamic_bitset<> &atomsInPlay,
848 const boost::dynamic_bitset<> &bondsInPlay,
853 bool useSpecial =
false,
bool useChirality =
false,
854 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
855 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
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
CXXAtomIterator< const MolGraph, Atom *const, MolGraph::adjacency_iterator > atomNeighbors(Atom const *at) const
#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)
void freeCanonAtoms(std::vector< Canon::canon_atom > &atoms)
RDKIT_GRAPHMOL_EXPORT void CreateSinglePartition(unsigned int nAtoms, int *order, int *count, canon_atom *atoms)
RDKIT_GRAPHMOL_EXPORT void initCanonAtoms(const ROMol &mol, std::vector< Canon::canon_atom > &atoms, bool includeChirality=true)
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)
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 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)
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)
RDKIT_GRAPHMOL_EXPORT void rankMolAtoms(const ROMol &mol, std::vector< unsigned int > &res, bool breakTies=true, bool includeChirality=true, bool includeIsotopes=true)
RDKIT_RDGENERAL_EXPORT const std::string _CIPCode
RDKIT_RDGENERAL_EXPORT const std::string molAtomMapNumber
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::vector< int > revistedNeighbors
std::vector< int > neighborNum