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{
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) {
172 bondholder::compare(dp_atoms[i].bonds[ii], dp_atoms[j].bonds[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) {
241 bondholder::compare(dp_atoms[i].bonds[ii], dp_atoms[j].bonds[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()) {
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;
271 if (
perm.size() == dp_atoms[i].atom->getDegree()) {
272 auto ctag = dp_atoms[i].atom->getChiralTag();
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;
321 dp_atoms[i].atom->getPropIfPresent(common_properties::molAtomMapNumber,
323 dp_atoms[j].atom->getPropIfPresent(common_properties::molAtomMapNumber,
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();
505 bondholder::compare(dp_atoms[i].bonds[ii], dp_atoms[j].bonds[ii]);
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 =
539 std::sort(nbrs.begin(), nbrs.end(), bondholder::greater);
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) {
578 if (dp_atoms[i].atom->getPropIfPresent(common_properties::_CIPCode,
580 ivi = cipCode ==
"R" ? 2 : 1;
582 if (dp_atoms[j].atom->getPropIfPresent(common_properties::_CIPCode,
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();
622 int cmp = bondholder::compare(
628 for (
unsigned int ii = 0;
629 ii < dp_atoms[i].bonds.size() && ii < dp_atoms[j].bonds.size();
632 bondholder::compare(dp_atoms[i].bonds[ii], dp_atoms[j].bonds[ii]);
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>
703 for (
int k = 0;
k <
len; ++
k) {
710 for (i =
count[index]; i <
len; i++) {
720 for (
unsigned j = 0;
j < atoms[index].
degree; ++
j) {
728 for (i =
count[index]; i <
len; i++) {
730 for (
unsigned j = 0;
j < atoms[index].
degree; ++
j) {
749template <
typename CompareFunc>
760 for (
unsigned int i = 0; i <
nAtoms; i++) {
766 index =
order[offset];
767 atoms[index].
index = offset;
772 if (atoms[index].degree < 1) {
775 for (
unsigned j = 0;
j < atoms[index].
degree; ++
j) {
810 std::vector<unsigned int> &
res,
811 bool breakTies =
true,
816 const ROMol &mol, std::vector<unsigned int> &
res,
819 const std::vector<std::string> *atomSymbols,
820 const std::vector<std::string> *
bondSymbols,
bool breakTies,
824 const ROMol &mol, std::vector<unsigned int> &
res,
827 const std::vector<std::string> *atomSymbols =
nullptr,
835 std::vector<unsigned int> &
res);
838 std::vector<Canon::canon_atom> &atoms,
843 std::vector<Canon::canon_atom> &atoms,
845 const std::vector<std::string> *atomSymbols,
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
@ 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)
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)
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::vector< int > revistedNeighbors
std::vector< int > neighborNum