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{
118 canon_atom *atoms, std::vector<bondholder> &nbrs);
121 canon_atom *atoms, std::vector<bondholder> &nbrs,
unsigned int atomIdx,
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) {
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) {
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()) {
253unsigned int getChiralRank(
const ROMol *dp_mol, canon_atom *dp_atoms,
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;
261 if (std::find(perm.begin(), perm.end(), rnk) != perm.end()) {
267 if (perm.size() == dp_atoms[i].atom->getDegree()) {
268 auto ctag = dp_atoms[i].atom->getChiralTag();
269 if (ctag == Atom::ChiralType::CHI_TETRAHEDRAL_CW ||
270 ctag == Atom::ChiralType::CHI_TETRAHEDRAL_CCW) {
271 auto sortedPerm = perm;
272 std::sort(sortedPerm.begin(), sortedPerm.end());
274 res = ctag == Atom::ChiralType::CHI_TETRAHEDRAL_CW ? 2 : 1;
276 res = res == 2 ? 1 : 2;
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) {
315 int molAtomMapNumber_i = 0;
316 int molAtomMapNumber_j = 0;
321 if (molAtomMapNumber_i < molAtomMapNumber_j) {
323 }
else if (molAtomMapNumber_i > molAtomMapNumber_j) {
327 ivi = dp_atoms[i].degree;
328 ivj = dp_atoms[j].degree;
331 }
else if (ivi > ivj) {
334 if (dp_atoms[i].p_symbol && dp_atoms[j].p_symbol) {
335 if (*(dp_atoms[i].p_symbol) < *(dp_atoms[j].p_symbol)) {
337 }
else if (*(dp_atoms[i].p_symbol) > *(dp_atoms[j].p_symbol)) {
345 ivi = dp_atoms[i].atom->getAtomicNum();
346 ivj = dp_atoms[j].atom->getAtomicNum();
349 }
else if (ivi > ivj) {
353 if (df_useIsotopes) {
354 ivi = dp_atoms[i].atom->getIsotope();
355 ivj = dp_atoms[j].atom->getIsotope();
358 }
else if (ivi > ivj) {
364 ivi = dp_atoms[i].totalNumHs;
365 ivj = dp_atoms[j].totalNumHs;
368 }
else if (ivi > ivj) {
372 ivi = dp_atoms[i].atom->getFormalCharge();
373 ivj = dp_atoms[j].atom->getFormalCharge();
376 }
else if (ivi > ivj) {
380 if (df_useChirality) {
382 ivi = dp_atoms[i].whichStereoGroup;
384 ivj = dp_atoms[j].whichStereoGroup;
388 }
else if (ivj && !ivi) {
390 }
else if (ivi && ivj) {
391 ivi =
static_cast<unsigned int>(dp_atoms[i].typeOfStereoGroup);
392 ivj =
static_cast<unsigned int>(dp_atoms[j].typeOfStereoGroup);
395 }
else if (ivi > ivj) {
398 ivi = dp_atoms[i].whichStereoGroup - 1;
399 ivj = dp_atoms[j].whichStereoGroup - 1;
401 std::set<unsigned int> sgi;
403 sgi.insert(dp_atoms[sgat->getIdx()].index);
405 std::set<unsigned int> sgj;
407 sgj.insert(dp_atoms[sgat->getIdx()].index);
411 }
else if (sgi > sgj) {
421 ivi = dp_atoms[i].atom->getChiralTag() != 0;
422 ivj = dp_atoms[j].atom->getChiralTag() != 0;
425 }
else if (ivi > ivj) {
431 ivi = getChiralRank(dp_mol, dp_atoms, i);
434 ivj = getChiralRank(dp_mol, dp_atoms, j);
438 }
else if (ivi > ivj) {
445 if (df_useChiralityRings) {
447 ivi = getAtomRingNbrCode(i);
448 ivj = getAtomRingNbrCode(j);
451 }
else if (ivi > ivj) {
461 const boost::dynamic_bitset<> *dp_atomsInPlay{
nullptr},
462 *dp_bondsInPlay{
nullptr};
463 bool df_useNbrs{
false};
464 bool df_useIsotopes{
true};
465 bool df_useChirality{
true};
466 bool df_useChiralityRings{
true};
470 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
471 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
474 dp_atomsInPlay(atomsInPlay),
475 dp_bondsInPlay(bondsInPlay),
477 df_useIsotopes(true),
478 df_useChirality(true),
479 df_useChiralityRings(true) {}
481 if (dp_atomsInPlay && !((*dp_atomsInPlay)[i] || (*dp_atomsInPlay)[j])) {
484 int v = basecomp(i, j);
490 if (!dp_atomsInPlay || (*dp_atomsInPlay)[i]) {
493 if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
497 for (
unsigned int ii = 0;
498 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
507 if (dp_atoms[i].bonds.size() < dp_atoms[j].bonds.size()) {
509 }
else if (dp_atoms[i].bonds.size() > dp_atoms[j].bonds.size()) {
524 void getAtomNeighborhood(std::vector<bondholder> &nbrs)
const {
525 for (
unsigned j = 0; j < nbrs.size(); ++j) {
526 unsigned int nbrIdx = nbrs[j].nbrIdx;
531 const Atom *nbr = dp_atoms[nbrIdx].atom;
532 nbrs[j].nbrSymClass =
539 int basecomp(
int i,
int j)
const {
541 unsigned int ivi, ivj;
544 ivi = dp_atoms[i].index;
545 ivj = dp_atoms[j].index;
548 }
else if (ivi > ivj) {
553 ivi = dp_atoms[i].atom->getAtomicNum();
554 ivj = dp_atoms[j].atom->getAtomicNum();
557 }
else if (ivi > ivj) {
562 ivi = dp_atoms[i].atom->getIsotope();
563 ivj = dp_atoms[j].atom->getIsotope();
566 }
else if (ivi > ivj) {
576 ivi = cipCode ==
"R" ? 2 : 1;
580 ivj = cipCode ==
"R" ? 2 : 1;
584 }
else if (ivi > ivj) {
595 bool df_useNbrs{
false};
598 : dp_atoms(atoms), dp_mol(&m), df_useNbrs(false) {}
603 int v = basecomp(i, j);
609 getAtomNeighborhood(dp_atoms[i].bonds);
610 getAtomNeighborhood(dp_atoms[j].bonds);
615 for (
unsigned int ii = 0;
616 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
624 for (
unsigned int ii = 0;
625 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
633 if (dp_atoms[i].bonds.size() < dp_atoms[j].bonds.size()) {
635 }
else if (dp_atoms[i].bonds.size() > dp_atoms[j].bonds.size()) {
648template <
typename CompareFunc>
650 int mode,
int *order,
int *count,
int &activeset,
651 int *next,
int *changed,
char *touchedPartitions) {
663 while (activeset != -1) {
675 partition = activeset;
676 activeset = next[partition];
677 next[partition] = -2;
679 len = count[partition];
680 offset = atoms[partition].
index;
681 start = order + offset;
692 hanoisort(start, len, count, changed, compar);
699 for (
int k = 0; k < len; ++k) {
700 changed[start[k]] = 0;
706 for (i = count[index]; i < len; i++) {
709 symclass = offset + i;
711 atoms[index].
index = symclass;
716 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
717 changed[atoms[index].
nbrIds[j]] = 1;
724 for (i = count[index]; i < len; i++) {
726 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
727 unsigned int nbor = atoms[index].
nbrIds[j];
728 touchedPartitions[atoms[nbor].
index] = 1;
731 for (
unsigned int ii = 0; ii < nAtoms; ++ii) {
732 if (touchedPartitions[ii]) {
733 partition = order[ii];
734 if ((count[partition] > 1) && (next[partition] == -2)) {
735 next[partition] = activeset;
736 activeset = partition;
738 touchedPartitions[ii] = 0;
745template <
typename CompareFunc>
747 int mode,
int *order,
int *count,
int &activeset,
int *next,
748 int *changed,
char *touchedPartitions) {
756 for (
unsigned int i = 0; i < nAtoms; i++) {
757 partition = order[i];
758 oldPart = atoms[partition].
index;
759 while (count[partition] > 1) {
760 len = count[partition];
761 offset = atoms[partition].
index + len - 1;
762 index = order[offset];
763 atoms[index].
index = offset;
764 count[partition] = len - 1;
768 if (atoms[index].degree < 1) {
771 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
772 unsigned int nbor = atoms[index].
nbrIds[j];
773 touchedPartitions[atoms[nbor].
index] = 1;
777 for (
unsigned int ii = 0; ii < nAtoms; ++ii) {
778 if (touchedPartitions[ii]) {
779 int npart = order[ii];
780 if ((count[npart] > 1) && (next[npart] == -2)) {
781 next[npart] = activeset;
784 touchedPartitions[ii] = 0;
788 changed, touchedPartitions);
791 if (atoms[partition].index != oldPart) {
798 int *order,
int *count,
802 int *count,
int &activeset,
803 int *next,
int *changed);
806 std::vector<unsigned int> &res,
807 bool breakTies =
true,
808 bool includeChirality =
true,
809 bool includeIsotopes =
true);
812 const ROMol &mol, std::vector<unsigned int> &res,
813 const boost::dynamic_bitset<> &atomsInPlay,
814 const boost::dynamic_bitset<> &bondsInPlay,
815 const std::vector<std::string> *atomSymbols,
816 const std::vector<std::string> *bondSymbols,
bool breakTies,
817 bool includeChirality,
bool includeIsotope);
820 const ROMol &mol, std::vector<unsigned int> &res,
821 const boost::dynamic_bitset<> &atomsInPlay,
822 const boost::dynamic_bitset<> &bondsInPlay,
823 const std::vector<std::string> *atomSymbols =
nullptr,
824 bool breakTies =
true,
bool includeChirality =
true,
825 bool includeIsotopes =
true) {
827 breakTies, includeChirality, includeIsotopes);
831 std::vector<unsigned int> &res);
834 std::vector<Canon::canon_atom> &atoms,
835 bool includeChirality =
true);
839 std::vector<Canon::canon_atom> &atoms,
840 bool includeChirality,
841 const std::vector<std::string> *atomSymbols,
842 const std::vector<std::string> *bondSymbols,
843 const boost::dynamic_bitset<> &atomsInPlay,
844 const boost::dynamic_bitset<> &bondsInPlay,
848 bool useSpecial =
false,
bool useChirality =
false,
849 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
850 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)
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::unique_ptr< int[]> nbrIds
std::vector< int > revistedNeighbors
std::vector< int > neighborNum