22#include <boost/dynamic_bitset.hpp>
23#include <boost/container/small_vector.hpp>
63 unsigned int nsc,
unsigned int bidx)
70 unsigned int nsc,
unsigned int bidx)
85 unsigned int div = 1) {
88 if (symbolCompare != 0) {
134 canon_atom *atoms, std::vector<bondholder> &nbrs);
139 canon_atom *atoms, std::vector<bondholder> &nbrs,
unsigned int atomIdx,
140 std::vector<std::pair<unsigned int, unsigned int>> &result);
143 std::vector<std::pair<unsigned int, unsigned int>> &result);
166 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
167 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
186 for (
unsigned int ii = 0;
195 std::vector<std::pair<unsigned int, unsigned int>> swapsi;
196 std::vector<std::pair<unsigned int, unsigned int>> swapsj;
204 for (
unsigned int ii = 0; ii < swapsi.size() && ii < swapsj.size(); ++ii) {
205 int cmp = swapsi[ii].second - swapsj[ii].second;
226 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
227 const boost::dynamic_bitset<> *bondsInPlay =
nullptr)
258 for (
unsigned int ii = 0;
277unsigned int getChiralRank(
const ROMol *dp_mol, canon_atom *dp_atoms,
279 unsigned int res = 0;
280 std::vector<unsigned int> perm;
281 perm.reserve(dp_atoms[i].atom->getDegree());
282 for (
const auto nbr : dp_mol->
atomNeighbors(dp_atoms[i].atom)) {
283 auto rnk = dp_atoms[nbr->getIdx()].index;
285 if (std::find(perm.begin(), perm.end(), rnk) != perm.end()) {
291 if (perm.size() == dp_atoms[i].atom->getDegree()) {
292 auto ctag = dp_atoms[i].atom->getChiralTag();
295 auto sortedPerm = perm;
296 std::sort(sortedPerm.begin(), sortedPerm.end());
300 res = res == 2 ? 1 : 2;
308 unsigned int getAtomRingNbrCode(
unsigned int i)
const {
313 const std::span<const int> nbrs =
dp_atoms[i].nbrIds;
314 unsigned int code = 0;
315 for (
unsigned j = 0; j <
dp_atoms[i].degree; ++j) {
316 if (
dp_atoms[nbrs[j]].isRingStereoAtom) {
317 code +=
dp_atoms[nbrs[j]].index * 10000 + 1;
323 int basecomp(
int i,
int j)
const {
324 unsigned int ivi, ivj;
331 }
else if (ivi > ivj) {
337 int rankingNumber_i = 0;
338 int rankingNumber_j = 0;
343 if (rankingNumber_i < rankingNumber_j) {
345 }
else if (rankingNumber_i > rankingNumber_j) {
352 int molAtomMapNumber_i = 0;
353 int molAtomMapNumber_j = 0;
364 if (molAtomMapNumber_i < molAtomMapNumber_j) {
366 }
else if (molAtomMapNumber_i > molAtomMapNumber_j) {
375 }
else if (ivi > ivj) {
383 ivi =
dp_atoms[i].atom->getAtomicNum();
384 ivj =
dp_atoms[j].atom->getAtomicNum();
387 }
else if (ivi > ivj) {
392 ivi =
dp_atoms[i].atom->getIsotope();
393 ivj =
dp_atoms[j].atom->getIsotope();
396 }
else if (ivi > ivj) {
406 }
else if (ivi > ivj) {
410 ivi =
dp_atoms[i].atom->getFormalCharge();
411 ivj =
dp_atoms[j].atom->getFormalCharge();
414 }
else if (ivi > ivj) {
425 }
else if (ivi > ivj) {
438 }
else if (ivj && !ivi) {
440 }
else if (ivi && ivj) {
441 auto iType =
dp_atoms[i].typeOfStereoGroup;
442 auto jType =
dp_atoms[j].typeOfStereoGroup;
445 }
else if (iType > jType) {
450 std::set<unsigned int> sgi;
451 for (
const auto sgat :
452 dp_mol->getStereoGroups()[ivi - 1].getAtoms()) {
453 sgi.insert(
dp_atoms[sgat->getIdx()].index);
455 std::set<unsigned int> sgj;
456 for (
const auto sgat :
457 dp_mol->getStereoGroups()[ivj - 1].getAtoms()) {
458 sgj.insert(
dp_atoms[sgat->getIdx()].index);
462 }
else if (sgi > sgj) {
471 }
else if (ivi > ivj) {
483 ivi =
dp_atoms[i].atom->getChiralTag() != 0;
484 ivj =
dp_atoms[j].atom->getChiralTag() != 0;
487 }
else if (ivi > ivj) {
500 }
else if (ivi > ivj) {
509 ivi = getAtomRingNbrCode(i);
510 ivj = getAtomRingNbrCode(j);
513 }
else if (ivi > ivj) {
538 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
539 const boost::dynamic_bitset<> *bondsInPlay =
nullptr,
558 v = ordering < 0 ? -1 : 1;
576 for (
unsigned int ii = 0;
604 for (
unsigned j = 0; j < nbrs.size(); ++j) {
605 unsigned int nbrIdx = nbrs[j].nbrIdx;
611 nbrs[j].nbrSymClass =
618 int basecomp(
int i,
int j)
const {
620 unsigned int ivi, ivj;
627 }
else if (ivi > ivj) {
632 ivi =
dp_atoms[i].atom->getAtomicNum();
633 ivj =
dp_atoms[j].atom->getAtomicNum();
636 }
else if (ivi > ivj) {
641 ivi =
dp_atoms[i].atom->getIsotope();
642 ivj =
dp_atoms[j].atom->getIsotope();
645 }
else if (ivi > ivj) {
655 ivi = cipCode ==
"R" ? 2 : 1;
659 ivj = cipCode ==
"R" ? 2 : 1;
663 }
else if (ivi > ivj) {
682 int v = basecomp(i, j);
688 getAtomNeighborhood(
dp_atoms[i].bonds);
689 getAtomNeighborhood(
dp_atoms[j].bonds);
694 for (
unsigned int ii = 0;
703 for (
unsigned int ii = 0;
727template <
typename CompareFunc>
729 int mode, std::vector<int> &order,
730 std::vector<int> &count,
int &activeset,
731 std::vector<int> &next, std::vector<int> &changed,
732 std::vector<char> &touchedPartitions,
733 std::vector<int> *hanoiTemp =
nullptr) {
735 std::vector<int> localHanoiTemp;
737 localHanoiTemp.resize(nAtoms);
738 hanoiTemp = &localHanoiTemp;
746 PRECONDITION(hanoiTemp->size() >= nAtoms,
"hanoi scratch is too small");
750 while (activeset != -1) {
762 partition = activeset;
763 activeset = next[partition];
764 next[partition] = -2;
766 len = count[partition];
767 offset = atoms[partition].
index;
768 auto start = std::span<int>(&order[offset], len);
780 changed.data(), compar)) {
781 std::copy_n(hanoiTemp->begin(), len, start.begin());
789 for (
int k = 0; k < len; ++k) {
790 changed[start[k]] = 0;
796 for (i = count[index]; i < len; i++) {
799 symclass = offset + i;
801 atoms[index].
index = symclass;
806 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
807 changed[atoms[index].
nbrIds[j]] = 1;
814 for (i = count[index]; i < len; i++) {
816 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
817 unsigned int nbor = atoms[index].
nbrIds[j];
818 touchedPartitions[atoms[nbor].
index] = 1;
821 for (
unsigned int ii = 0; ii < nAtoms; ++ii) {
822 if (touchedPartitions[ii]) {
823 partition = order[ii];
824 if ((count[partition] > 1) && (next[partition] == -2)) {
825 next[partition] = activeset;
826 activeset = partition;
828 touchedPartitions[ii] = 0;
835template <
typename CompareFunc>
837 int mode, std::vector<int> &order, std::vector<int> &count,
838 int &activeset, std::vector<int> &next,
839 std::vector<int> &changed, std::vector<char> &touchedPartitions,
840 std::vector<int> *hanoiTemp =
nullptr) {
848 for (
unsigned int i = 0; i < nAtoms; i++) {
849 partition = order[i];
850 oldPart = atoms[partition].
index;
851 while (count[partition] > 1) {
852 len = count[partition];
853 offset = atoms[partition].
index + len - 1;
854 index = order[offset];
855 atoms[index].
index = offset;
856 count[partition] = len - 1;
860 if (atoms[index].degree < 1) {
863 for (
unsigned j = 0; j < atoms[index].
degree; ++j) {
864 unsigned int nbor = atoms[index].
nbrIds[j];
865 touchedPartitions[atoms[nbor].
index] = 1;
869 for (
unsigned int ii = 0; ii < nAtoms; ++ii) {
870 if (touchedPartitions[ii]) {
871 int npart = order[ii];
872 if ((count[npart] > 1) && (next[npart] == -2)) {
873 next[npart] = activeset;
876 touchedPartitions[ii] = 0;
880 changed, touchedPartitions, hanoiTemp);
883 if (atoms[partition].index != oldPart) {
890 std::vector<int> &order,
891 std::vector<int> &count,
895 unsigned int nAtoms, std::vector<int> &order, std::vector<int> &count,
896 int &activeset, std::vector<int> &next, std::vector<int> &changed);
900 const ROMol &mol, std::vector<unsigned int> &res,
bool breakTies =
true,
901 bool includeChirality =
true,
bool includeIsotopes =
true,
902 bool includeAtomMaps =
true,
bool includeChiralPresence =
false,
903 bool includeStereoGroups =
true,
bool useNonStereoRanks =
false,
904 bool includeRingStereo =
true);
908 const ROMol &mol, std::vector<unsigned int> &res,
909 const boost::dynamic_bitset<> &atomsInPlay,
910 const boost::dynamic_bitset<> &bondsInPlay,
911 const std::vector<std::string> *atomSymbols,
912 const std::vector<std::string> *bondSymbols,
bool breakTies,
913 bool includeChirality,
bool includeIsotope,
bool includeAtomMaps,
914 bool includeChiralPresence,
bool includeRingStereo =
true);
918 const ROMol &mol, std::vector<unsigned int> &res,
919 const boost::dynamic_bitset<> &atomsInPlay,
920 const boost::dynamic_bitset<> &bondsInPlay,
921 const std::vector<std::string> *atomSymbols =
nullptr,
922 bool breakTies =
true,
bool includeChirality =
true,
923 bool includeIsotopes =
true,
bool includeAtomMaps =
true,
924 bool includeChiralPresence =
false,
bool includeRingStereo =
true) {
926 breakTies, includeChirality, includeIsotopes,
927 includeAtomMaps, includeChiralPresence, includeRingStereo);
931 std::vector<unsigned int> &res);
934 std::vector<Canon::canon_atom> &atoms,
935 std::span<int> neighborIds,
936 bool includeChirality =
true,
937 bool includeStereoGroups =
true);
941 std::vector<Canon::canon_atom> &atoms,
942 bool includeChirality,
943 const std::vector<std::string> *atomSymbols,
944 const std::vector<std::string> *bondSymbols,
945 const boost::dynamic_bitset<> &atomsInPlay,
946 const boost::dynamic_bitset<> &bondsInPlay,
947 std::span<int> neighborIds,
bool needsInit);
950 bool useSpecial =
false,
bool useChirality =
false,
951 bool includeRingStereo =
true,
952 const boost::dynamic_bitset<> *atomsInPlay =
nullptr,
953 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.
@ CHI_TETRAHEDRAL_CW
tetrahedral: clockwise rotation (SMILES @@)
@ CHI_UNSPECIFIED
chirality that hasn't been specified
@ CHI_TETRAHEDRAL_CCW
tetrahedral: counter-clockwise rotation (SMILES
int getAtomicNum() const
returns our atomic number
BondStereo
the nature of the bond's stereochem (for cis/trans)
const boost::dynamic_bitset * dp_bondsInPlay
bool df_useAtomMapsOnDummies
const AtomCompareCode * dp_compareCodes
int operator()(int i, int j) const
const boost::dynamic_bitset * dp_atomsInPlay
bool df_useNonStereoRanks
bool df_useChiralityRings
AtomCompareFunctor(Canon::canon_atom *atoms, const ROMol &m, const boost::dynamic_bitset<> *atomsInPlay=nullptr, const boost::dynamic_bitset<> *bondsInPlay=nullptr, const AtomCompareCode *compareCodes=nullptr)
bool df_useChiralPresence
Canon::canon_atom * dp_atoms
ChiralAtomCompareFunctor(Canon::canon_atom *atoms, const ROMol &m)
int operator()(int i, int j) const
ChiralAtomCompareFunctor()
Canon::canon_atom * dp_atoms
const boost::dynamic_bitset * dp_atomsInPlay
int operator()(int i, int j) const
const boost::dynamic_bitset * dp_bondsInPlay
Canon::canon_atom * dp_atoms
SpecialChiralityAtomCompareFunctor(Canon::canon_atom *atoms, const ROMol &m, const boost::dynamic_bitset<> *atomsInPlay=nullptr, const boost::dynamic_bitset<> *bondsInPlay=nullptr)
SpecialChiralityAtomCompareFunctor()
Canon::canon_atom * dp_atoms
SpecialSymmetryAtomCompareFunctor()
const boost::dynamic_bitset * dp_bondsInPlay
const boost::dynamic_bitset * dp_atomsInPlay
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
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 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, std::span< int > neighborIds, bool needsInit)
void rankWithFunctor(T &ftor, bool breakTies, std::vector< int > &order, bool useSpecial=false, bool useChirality=false, bool includeRingStereo=true, const boost::dynamic_bitset<> *atomsInPlay=nullptr, const boost::dynamic_bitset<> *bondsInPlay=nullptr)
void RefinePartitions(const ROMol &mol, canon_atom *atoms, CompareFunc compar, int mode, std::vector< int > &order, std::vector< int > &count, int &activeset, std::vector< int > &next, std::vector< int > &changed, std::vector< char > &touchedPartitions, std::vector< int > *hanoiTemp=nullptr)
const unsigned int ATNUM_CLASS_OFFSET
RDKIT_GRAPHMOL_EXPORT void CreateSinglePartition(unsigned int nAtoms, std::vector< int > &order, std::vector< int > &count, canon_atom *atoms)
RDKIT_GRAPHMOL_EXPORT void updateAtomNeighborNumSwaps(canon_atom *atoms, std::vector< bondholder > &nbrs, unsigned int atomIdx, std::vector< std::pair< unsigned int, unsigned int > > &result)
boost::container::small_vector< bondholder, 4 > BondholderVector
RDKIT_GRAPHMOL_EXPORT void ActivatePartitions(unsigned int nAtoms, std::vector< int > &order, std::vector< int > &count, int &activeset, std::vector< int > &next, std::vector< int > &changed)
void BreakTies(const ROMol &mol, canon_atom *atoms, CompareFunc compar, int mode, std::vector< int > &order, std::vector< int > &count, int &activeset, std::vector< int > &next, std::vector< int > &changed, std::vector< char > &touchedPartitions, std::vector< int > *hanoiTemp=nullptr)
RDKIT_GRAPHMOL_EXPORT void chiralRankMolAtoms(const ROMol &mol, std::vector< unsigned int > &res)
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, bool includeRingStereo=true)
Note that atom maps on dummy atoms will always be used.
RDKIT_GRAPHMOL_EXPORT void updateAtomNeighborIndex(canon_atom *atoms, std::vector< bondholder > &nbrs)
RDKIT_GRAPHMOL_EXPORT void initCanonAtoms(const ROMol &mol, std::vector< Canon::canon_atom > &atoms, std::span< int > neighborIds, bool includeChirality=true, bool includeStereoGroups=true)
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, bool includeRingStereo=true)
Note that atom maps on dummy atoms will always be used.
constexpr std::string_view _CanonicalRankingNumber
constexpr std::string_view _CIPCode
constexpr std::string_view molAtomMapNumber
bool hanoi(int *base, int nel, int *temp, int *count, int *changed, CompareFunc compar)
unsigned int countSwapsToInterconvert(const T &ref, T probe)
auto operator<=>(const AtomCompareCode &) const =default
const std::string * p_symbol
static bool greater(const bondholder &lhs, const bondholder &rhs)
bool operator<(const bondholder &o) const
const canon_atom * controllingAtoms[4]
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)
StereoGroupType typeOfStereoGroup
std::vector< int > revistedNeighbors
std::vector< int > neighborNum
const std::string * p_symbol
unsigned int whichStereoGroup