synkit 1.6.5__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- synkit/CRN/Benchmark/__init__.py +53 -0
- synkit/CRN/Benchmark/crosschecks.py +13 -0
- synkit/CRN/Benchmark/kegg.py +12 -0
- synkit/CRN/Benchmark/networks.py +13 -0
- synkit/CRN/Benchmark/scaling.py +13 -0
- synkit/CRN/Benchmark/validate.py +13 -0
- synkit/CRN/Construct/__init__.py +16 -0
- synkit/CRN/Construct/abstract.py +668 -0
- synkit/CRN/Construct/arity.py +36 -0
- synkit/CRN/Construct/builder.py +619 -0
- synkit/CRN/Construct/derivation.py +63 -0
- synkit/CRN/Construct/flattener.py +100 -0
- synkit/CRN/Construct/keys.py +14 -0
- synkit/CRN/Construct/mixtures.py +117 -0
- synkit/CRN/Construct/rdkit_worker.py +69 -0
- synkit/CRN/Construct/smiles.py +99 -0
- synkit/CRN/Construct/state.py +31 -0
- synkit/CRN/Construct/strategy.py +75 -0
- synkit/CRN/Construct/worker.py +42 -0
- synkit/CRN/IO/__init__.py +36 -0
- synkit/CRN/IO/sbml.py +925 -0
- synkit/CRN/Pathway/__init__.py +72 -0
- synkit/CRN/Pathway/_adapter.py +333 -0
- synkit/CRN/Pathway/pathfinder.py +500 -0
- synkit/CRN/Pathway/reachability.py +796 -0
- synkit/CRN/Pathway/realizability.py +1322 -0
- synkit/CRN/Petrinet/__init__.py +93 -0
- synkit/CRN/Petrinet/analyzer.py +486 -0
- synkit/CRN/Petrinet/minimal_semiflows.py +436 -0
- synkit/CRN/Petrinet/net.py +1041 -0
- synkit/CRN/Petrinet/persistence.py +97 -0
- synkit/CRN/Petrinet/semiflows.py +483 -0
- synkit/CRN/Petrinet/siphon_search.py +402 -0
- synkit/CRN/Petrinet/structure.py +286 -0
- synkit/CRN/Props/__init__.py +130 -0
- synkit/CRN/Props/_rank.py +29 -0
- synkit/CRN/Props/deficiency.py +953 -0
- synkit/CRN/Props/dynamics.py +832 -0
- synkit/CRN/Props/helper.py +151 -0
- synkit/CRN/Props/stoich.py +751 -0
- synkit/CRN/Props/thermo.py +584 -0
- synkit/CRN/Query/__init__.py +66 -0
- synkit/CRN/Query/cache.py +41 -0
- synkit/CRN/Query/kegg_api.py +99 -0
- synkit/CRN/Query/kegg_extract.py +714 -0
- synkit/CRN/Query/kegg_impute.py +707 -0
- synkit/CRN/Query/kegg_parse.py +480 -0
- synkit/CRN/Query/to_syncrn.py +290 -0
- synkit/CRN/README.md +234 -0
- synkit/CRN/Structure/__init__.py +12 -0
- synkit/CRN/Structure/_graph_io.py +713 -0
- synkit/CRN/Structure/_matrices.py +88 -0
- synkit/CRN/Structure/_parse.py +544 -0
- synkit/CRN/Structure/reaction.py +237 -0
- synkit/CRN/Structure/rule.py +55 -0
- synkit/CRN/Structure/species.py +46 -0
- synkit/CRN/Structure/syncrn.py +929 -0
- synkit/CRN/Symmetry/__init__.py +20 -0
- synkit/CRN/Symmetry/_common.py +1059 -0
- synkit/CRN/Symmetry/_ir.py +940 -0
- synkit/CRN/Symmetry/automorphism.py +472 -0
- synkit/CRN/Symmetry/canon.py +441 -0
- synkit/CRN/Symmetry/isomorphism.py +412 -0
- synkit/CRN/Symmetry/symmetry.py +61 -0
- synkit/CRN/Symmetry/wl_canon.py +967 -0
- synkit/CRN/Visualize/__init__.py +11 -0
- synkit/CRN/Visualize/labels.py +113 -0
- synkit/CRN/Visualize/layout.py +708 -0
- synkit/CRN/Visualize/palette.py +292 -0
- synkit/CRN/Visualize/validation.py +122 -0
- synkit/CRN/Visualize/vis.py +1152 -0
- synkit/CRN/__init__.py +233 -0
- synkit/CRN/_build.py +50 -0
- synkit/CRN/_native_build.py +175 -0
- synkit/CRN/analysis.py +629 -0
- synkit/CRN/backend.py +74 -0
- synkit/CRN/cpp/CMakeLists.txt +58 -0
- synkit/CRN/cpp/algebra.cpp +46 -0
- synkit/CRN/cpp/closure.cpp +29 -0
- synkit/CRN/cpp/exact.h +55 -0
- synkit/CRN/cpp/pathway.cpp +46 -0
- synkit/CRN/cpp/semiflows.cpp +209 -0
- synkit/CRN/cpp/structural.cpp +240 -0
- synkit/CRN/cpp/symmetry.cpp +45 -0
- synkit/CRN/cpp/write_manifest.cmake +28 -0
- synkit/CRN/kinds.py +137 -0
- synkit/CRN/lib/synkit_crn.dll +0 -0
- synkit/CRN/lib/synkit_crn.json +33 -0
- synkit/CRN/native.py +388 -0
- synkit/CRN/native_analysis.py +459 -0
- synkit/Chem/Cluster/__init__.py +0 -0
- synkit/Chem/Cluster/butina.py +140 -0
- synkit/Chem/Fingerprint/__init__.py +0 -0
- synkit/Chem/Fingerprint/fp_calculator.py +155 -0
- synkit/Chem/Fingerprint/smiles_featurizer.py +258 -0
- synkit/Chem/Fingerprint/transformation_fp.py +139 -0
- synkit/Chem/Mapper/README.rst +43 -0
- synkit/Chem/Mapper/__init__.py +255 -0
- synkit/Chem/Mapper/_compat.py +130 -0
- synkit/Chem/Mapper/adapters/__init__.py +1 -0
- synkit/Chem/Mapper/adapters/prediction.py +126 -0
- synkit/Chem/Mapper/adapters/template.py +412 -0
- synkit/Chem/Mapper/chem/__init__.py +52 -0
- synkit/Chem/Mapper/chem/aam.py +673 -0
- synkit/Chem/Mapper/chem/blind.py +160 -0
- synkit/Chem/Mapper/chem/its.py +309 -0
- synkit/Chem/Mapper/chem/smiles.py +564 -0
- synkit/Chem/Mapper/graph/__init__.py +66 -0
- synkit/Chem/Mapper/graph/automorphism.py +395 -0
- synkit/Chem/Mapper/graph/blockcut.py +98 -0
- synkit/Chem/Mapper/graph/labeled_graph.py +104 -0
- synkit/Chem/Mapper/graph/refine.py +176 -0
- synkit/Chem/Mapper/graph/synkit_adapter.py +110 -0
- synkit/Chem/Mapper/io/__init__.py +13 -0
- synkit/Chem/Mapper/io/idxmapstr.py +82 -0
- synkit/Chem/Mapper/mapper.py +685 -0
- synkit/Chem/Mapper/reaction_search.py +554 -0
- synkit/Chem/Mapper/reporting/__init__.py +1 -0
- synkit/Chem/Mapper/reporting/alternatives.py +451 -0
- synkit/Chem/Mapper/reporting/analysis.py +681 -0
- synkit/Chem/Mapper/reporting/native_analysis.py +485 -0
- synkit/Chem/Mapper/reporting/spectrum.py +642 -0
- synkit/Chem/Mapper/solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/__init__.py +141 -0
- synkit/Chem/Mapper/solvers/exact/assignment/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_certificate.py +113 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_domains.py +162 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_verification.py +58 -0
- synkit/Chem/Mapper/solvers/exact/assignment/incremental_assignment.py +247 -0
- synkit/Chem/Mapper/solvers/exact/certificate.py +128 -0
- synkit/Chem/Mapper/solvers/exact/core.py +183 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/bounds.py +319 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/exhaustive.py +179 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/inputs.py +283 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/records.py +242 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/search.py +1025 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/verify.py +378 -0
- synkit/Chem/Mapper/solvers/exact/edit_support.py +375 -0
- synkit/Chem/Mapper/solvers/exact/hybrid.py +224 -0
- synkit/Chem/Mapper/solvers/exact/hydrogen.py +264 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/branching.py +499 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumerate.py +1050 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumeration_result.py +30 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/kernel.py +256 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/milp.py +194 -0
- synkit/Chem/Mapper/solvers/exact/native/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/native/build.py +154 -0
- synkit/Chem/Mapper/solvers/exact/native/candidates.py +593 -0
- synkit/Chem/Mapper/solvers/exact/native/canonical.py +396 -0
- synkit/Chem/Mapper/solvers/exact/native/disk_frontier.py +415 -0
- synkit/Chem/Mapper/solvers/exact/native/frontier.py +390 -0
- synkit/Chem/Mapper/solvers/exact/native/hydrogen_quotient.py +213 -0
- synkit/Chem/Mapper/solvers/exact/native/its.py +528 -0
- synkit/Chem/Mapper/solvers/exact/native/native_distance.cpp +2803 -0
- synkit/Chem/Mapper/solvers/exact/native/orbit_aggregation.py +328 -0
- synkit/Chem/Mapper/solvers/exact/native/parallel.py +205 -0
- synkit/Chem/Mapper/solvers/exact/native/pmcd.py +203 -0
- synkit/Chem/Mapper/solvers/exact/native/runtime.py +40 -0
- synkit/Chem/Mapper/solvers/exact/native/search.py +294 -0
- synkit/Chem/Mapper/solvers/exact/native/separator.py +224 -0
- synkit/Chem/Mapper/solvers/exact/native_build.py +12 -0
- synkit/Chem/Mapper/solvers/exact/pabs/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/pabs/cost_lattice.py +43 -0
- synkit/Chem/Mapper/solvers/exact/pabs/factor_spectrum.py +110 -0
- synkit/Chem/Mapper/solvers/exact/pabs/multi_shell.py +368 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation.py +679 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_bounds.py +436 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_limits.py +13 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_search.py +856 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_symmetry.py +66 -0
- synkit/Chem/Mapper/solvers/exact/pabs/residual_typed_bonds.py +136 -0
- synkit/Chem/Mapper/solvers/exact/pabs/reward_frontier.py +201 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_bound.py +258 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_spectrum.py +308 -0
- synkit/Chem/Mapper/solvers/exact/pabs/sparse_reward_bound.py +207 -0
- synkit/Chem/Mapper/solvers/exact/pabs/suffix_spectrum.py +299 -0
- synkit/Chem/Mapper/solvers/exact/search.py +55 -0
- synkit/Chem/Mapper/solvers/exact/seeds/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed.py +104 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_fragments.py +148 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_relaxation.py +181 -0
- synkit/Chem/Mapper/solvers/exact/symmetry.py +223 -0
- synkit/Chem/Mapper/solvers/native/__init__.py +4 -0
- synkit/Chem/Mapper/solvers/native/assignment.py +99 -0
- synkit/Chem/Mapper/solvers/native/astar.py +22 -0
- synkit/Chem/Mapper/solvers/native/build.py +385 -0
- synkit/Chem/Mapper/solvers/native/classification.py +641 -0
- synkit/Chem/Mapper/solvers/native/core.py +378 -0
- synkit/Chem/Mapper/solvers/native/cpp/CMakeLists.txt +120 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/map_reaction.cpp +29 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/slap_graph.cpp +63 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/assignment/assignment.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/astar.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/bound.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/pmcd_witness.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/runtime.h +130 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/hydrogen/hydrogen.h +73 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mapper.h +175 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mces/mces.h +9 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/pabs/seed.h +34 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/reaction/reaction.h +30 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/sepdp/sepdp.h +21 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/slap.h +72 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/solvers/solvers.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/classification.h +140 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/cpabs.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/assignment/abb.cpp +302 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/CMakeLists.txt +12 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/README.md +47 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar.cpp +228 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar_graph.cpp +37 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/bound.cpp +212 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/dispatch.cpp +272 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/pmcd_witness.cpp +36 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/hydrogen/hydrogen.cpp +380 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/README.md +57 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/mces.cpp +287 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/bridge.cpp +334 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/chemical_floor.inc +181 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/endpoint_symmetry.inc +104 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/exact_helpers.h +20 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_assignment_certificate.h +165 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_certificate.h +125 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_model.h +365 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_provider.inc +319 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_rounding.inc +170 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_test_hooks.h +342 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/objective_reduction.inc +137 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/overlap_dual.inc +351 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/profile_seed.inc +214 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/seed_heuristics.inc +640 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_embedding.cpp +430 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_root_lp.h +176 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/test_hooks.inc +262 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/reaction/reaction.cpp +611 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/README.md +61 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/sepdp.cpp +253 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/slap.cpp +810 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/formulation.h +138 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/maxsat.cpp +526 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/ortools.cpp +475 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/seed.h +80 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/weighted_cnf.h +256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/README.md +43 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/dfs.cpp +123 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/edit_support.cpp +224 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification.cpp +553 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_pipeline.cpp +124 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_stream.h +13 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/cpabs.cpp +455 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/edge_deck.cpp +743 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naugraph.c +732 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.c +94 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.h +49 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.c +1771 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.h +133 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nautil.c +750 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naututil.h +355 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.c +1256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.h +1544 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.c +1131 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.h +70 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/sorttemplates.c +580 -0
- synkit/Chem/Mapper/solvers/native/hydrogen.py +711 -0
- synkit/Chem/Mapper/solvers/native/implicit.py +506 -0
- synkit/Chem/Mapper/solvers/native/implicit_certificate.py +187 -0
- synkit/Chem/Mapper/solvers/native/implicit_preparation.py +309 -0
- synkit/Chem/Mapper/solvers/native/lib/synkit_mapper.dll +0 -0
- synkit/Chem/Mapper/solvers/native/mces.py +16 -0
- synkit/Chem/Mapper/solvers/native/reaction.py +179 -0
- synkit/Chem/Mapper/solvers/native/reaction_build.py +277 -0
- synkit/Chem/Mapper/solvers/native/reaction_text.py +26 -0
- synkit/Chem/Mapper/solvers/native/runtime.py +242 -0
- synkit/Chem/Mapper/solvers/native/sepdp.py +47 -0
- synkit/Chem/Mapper/solvers/native/slap.py +266 -0
- synkit/Chem/Mapper/solvers/native/solvers.py +67 -0
- synkit/Chem/Mapper/solvers/native/stereo.py +86 -0
- synkit/Chem/Mapper/solvers/native/supporting.py +34 -0
- synkit/Chem/Mapper/solvers/native/symmetry.py +91 -0
- synkit/Chem/Mapper/solvers/slap/__init__.py +29 -0
- synkit/Chem/Mapper/solvers/slap/lap.py +174 -0
- synkit/Chem/Mapper/solvers/slap/sequential.py +696 -0
- synkit/Chem/Mapper/validation/__init__.py +1 -0
- synkit/Chem/Mapper/validation/aam_validator.py +442 -0
- synkit/Chem/Mapper/validation/annotations.py +274 -0
- synkit/Chem/Mapper/validation/bonds.py +124 -0
- synkit/Chem/Mapper/validation/cohorts.py +72 -0
- synkit/Chem/Mapper/validation/identifiability.py +150 -0
- synkit/Chem/Mapper/validation/numerical_scope.py +36 -0
- synkit/Chem/Mapper/validation/orbits.py +137 -0
- synkit/Chem/Molecule/__init__.py +0 -0
- synkit/Chem/Molecule/_chirality_loci.py +165 -0
- synkit/Chem/Molecule/_chirality_types.py +231 -0
- synkit/Chem/Molecule/_helical_loci.py +167 -0
- synkit/Chem/Molecule/_stereo_axis_evidence.py +202 -0
- synkit/Chem/Molecule/_stereo_element_detection.py +193 -0
- synkit/Chem/Molecule/_stereo_orientation_constraints.py +511 -0
- synkit/Chem/Molecule/_tetrahedral_carriers.py +63 -0
- synkit/Chem/Molecule/atom_features.py +379 -0
- synkit/Chem/Molecule/chirality.py +1041 -0
- synkit/Chem/Molecule/cip_assignment.py +569 -0
- synkit/Chem/Molecule/cip_ranking.py +843 -0
- synkit/Chem/Molecule/coordinate_stereo.py +503 -0
- synkit/Chem/Molecule/derived_stereo_naming.py +165 -0
- synkit/Chem/Molecule/descriptors.py +452 -0
- synkit/Chem/Molecule/formula.py +249 -0
- synkit/Chem/Molecule/global_stereo.py +175 -0
- synkit/Chem/Molecule/graph_annotator.py +300 -0
- synkit/Chem/Molecule/standardize.py +817 -0
- synkit/Chem/Molecule/stereo_evidence.py +179 -0
- synkit/Chem/Molecule/stereo_perception.py +1032 -0
- synkit/Chem/Molecule/valence.py +123 -0
- synkit/Chem/Reaction/Mapper/__init__.py +44 -0
- synkit/Chem/Reaction/__init__.py +20 -0
- synkit/Chem/Reaction/aam_validator.py +5 -0
- synkit/Chem/Reaction/balance_check.py +138 -0
- synkit/Chem/Reaction/canon_rsmi.py +249 -0
- synkit/Chem/Reaction/cleaning.py +58 -0
- synkit/Chem/Reaction/deionize.py +199 -0
- synkit/Chem/Reaction/explicit_h_audit.py +232 -0
- synkit/Chem/Reaction/fix_aam.py +64 -0
- synkit/Chem/Reaction/neutralize.py +207 -0
- synkit/Chem/Reaction/radical_wildcard.py +224 -0
- synkit/Chem/Reaction/standardize.py +203 -0
- synkit/Chem/Reaction/tautomerize.py +205 -0
- synkit/Chem/__init__.py +1 -0
- synkit/Chem/utils.py +315 -0
- synkit/Data/__init__.py +0 -0
- synkit/Data/aldol.json.gz +1 -0
- synkit/Data/gen_partial_aam.py +147 -0
- synkit/Data/paracetamol.json.gz +1 -0
- synkit/Graph/Canon/__init__.py +16 -0
- synkit/Graph/Canon/_native/__init__.py +13 -0
- synkit/Graph/Canon/_native/build.py +93 -0
- synkit/Graph/Canon/_native/lib/synkit_canon.dll +0 -0
- synkit/Graph/Canon/_native/prepare.py +49 -0
- synkit/Graph/Canon/_native/runtime.py +140 -0
- synkit/Graph/Canon/_native/search.py +137 -0
- synkit/Graph/Canon/canon_algs.py +228 -0
- synkit/Graph/Canon/canon_graph.py +531 -0
- synkit/Graph/Canon/cpp/CMakeLists.txt +42 -0
- synkit/Graph/Canon/cpp/README.md +123 -0
- synkit/Graph/Canon/cpp/examples/canonical_graph.cpp +16 -0
- synkit/Graph/Canon/cpp/include/synkit_canon/canon.h +85 -0
- synkit/Graph/Canon/cpp/src/canonical.cpp +391 -0
- synkit/Graph/Canon/cpp/src/symmetry.h +83 -0
- synkit/Graph/Canon/cpp/tests/symmetry.cpp +93 -0
- synkit/Graph/Canon/exact.py +1020 -0
- synkit/Graph/Canon/exact_refinement.py +368 -0
- synkit/Graph/Canon/nauty.py +143 -0
- synkit/Graph/Context/__init__.py +0 -0
- synkit/Graph/Context/hier_context.py +244 -0
- synkit/Graph/Context/radius_expand.py +252 -0
- synkit/Graph/FG/__init__.py +19 -0
- synkit/Graph/FG/api.py +39 -0
- synkit/Graph/FG/audit.py +155 -0
- synkit/Graph/FG/catalog.py +919 -0
- synkit/Graph/FG/detector.py +288 -0
- synkit/Graph/FG/model.py +97 -0
- synkit/Graph/FG/recognizers.py +274 -0
- synkit/Graph/FG/ring_system.py +154 -0
- synkit/Graph/Feature/Descriptors/topology.py +857 -0
- synkit/Graph/Feature/Fingerprint/__init__.py +0 -0
- synkit/Graph/Feature/Fingerprint/wl_rxn_fps.py +222 -0
- synkit/Graph/Feature/__init__.py +5 -0
- synkit/Graph/Feature/graph_descriptors.py +323 -0
- synkit/Graph/Feature/graph_fps.py +96 -0
- synkit/Graph/Feature/graph_signature.py +239 -0
- synkit/Graph/Feature/hash_fps.py +133 -0
- synkit/Graph/Feature/morgan_fps.py +88 -0
- synkit/Graph/Feature/path_fps.py +81 -0
- synkit/Graph/Feature/wl_hash.py +134 -0
- synkit/Graph/Fusion/__init__.py +85 -0
- synkit/Graph/Fusion/candidate.py +559 -0
- synkit/Graph/Fusion/constructor.py +877 -0
- synkit/Graph/Fusion/identity.py +184 -0
- synkit/Graph/Fusion/interface.py +700 -0
- synkit/Graph/Fusion/search.py +241 -0
- synkit/Graph/Hyrogen/__init__.py +6 -0
- synkit/Graph/Hyrogen/_misc.py +591 -0
- synkit/Graph/Hyrogen/hcomplete.py +995 -0
- synkit/Graph/Hyrogen/hcomplete_legacy.py +368 -0
- synkit/Graph/Hyrogen/hcompletion_algorithms.py +713 -0
- synkit/Graph/Hyrogen/hextend.py +570 -0
- synkit/Graph/Hyrogen/hextend_legacy.py +215 -0
- synkit/Graph/ITS/__init__.py +4 -0
- synkit/Graph/ITS/its_builder.py +120 -0
- synkit/Graph/ITS/its_construction.py +719 -0
- synkit/Graph/ITS/its_decompose.py +572 -0
- synkit/Graph/ITS/its_destruction.py +331 -0
- synkit/Graph/ITS/its_expand.py +1251 -0
- synkit/Graph/ITS/its_relabel.py +187 -0
- synkit/Graph/ITS/its_reverter.py +356 -0
- synkit/Graph/ITS/normalize_aam.py +145 -0
- synkit/Graph/ITS/partial_its.py +238 -0
- synkit/Graph/ITS/rc_extractor.py +656 -0
- synkit/Graph/ITS/stereo.py +74 -0
- synkit/Graph/MTG/__init__.py +107 -0
- synkit/Graph/MTG/gluing.py +451 -0
- synkit/Graph/MTG/history.py +928 -0
- synkit/Graph/MTG/inventory.py +118 -0
- synkit/Graph/MTG/local.py +447 -0
- synkit/Graph/MTG/mcs_matcher.py +246 -0
- synkit/Graph/MTG/mtg.py +611 -0
- synkit/Graph/MTG/mtg_explore.py +74 -0
- synkit/Graph/MTG/observation.py +209 -0
- synkit/Graph/MTG/process.py +577 -0
- synkit/Graph/MTG/queries.py +66 -0
- synkit/Graph/MTG/realization.py +95 -0
- synkit/Graph/MTG/series_parallel.py +107 -0
- synkit/Graph/MTG/utils.py +424 -0
- synkit/Graph/Matcher/__init__.py +10 -0
- synkit/Graph/Matcher/approx_mcs.py +1264 -0
- synkit/Graph/Matcher/auto_est.py +736 -0
- synkit/Graph/Matcher/automorphism.py +314 -0
- synkit/Graph/Matcher/batch_cluster.py +224 -0
- synkit/Graph/Matcher/dedup_matches.py +247 -0
- synkit/Graph/Matcher/graph_cluster.py +191 -0
- synkit/Graph/Matcher/graph_matcher.py +312 -0
- synkit/Graph/Matcher/graph_morphism.py +421 -0
- synkit/Graph/Matcher/mcs_matcher.py +804 -0
- synkit/Graph/Matcher/multi_turbo_iso.py +186 -0
- synkit/Graph/Matcher/orbit.py +284 -0
- synkit/Graph/Matcher/partial_matcher.py +694 -0
- synkit/Graph/Matcher/sing.py +544 -0
- synkit/Graph/Matcher/subgraph_matcher.py +812 -0
- synkit/Graph/Matcher/turbo_iso.py +272 -0
- synkit/Graph/Matcher/wl_sel.py +537 -0
- synkit/Graph/Mech/__init__.py +26 -0
- synkit/Graph/Mech/conversion.py +1466 -0
- synkit/Graph/Mech/conversion_debug.py +237 -0
- synkit/Graph/Mech/electron_accounting.py +200 -0
- synkit/Graph/Mech/lwg_editor.py +406 -0
- synkit/Graph/Mech/lwg_ops.py +313 -0
- synkit/Graph/Morphism/__init__.py +99 -0
- synkit/Graph/Morphism/constraints.py +460 -0
- synkit/Graph/Morphism/llg.py +999 -0
- synkit/Graph/Morphism/morphism.py +349 -0
- synkit/Graph/Morphism/stereo.py +258 -0
- synkit/Graph/Morphism/stereo_morphism.py +383 -0
- synkit/Graph/Morphism/stereo_morphism_helpers.py +957 -0
- synkit/Graph/Morphism/stereo_morphism_types.py +117 -0
- synkit/Graph/Stereo/__init__.py +376 -0
- synkit/Graph/Stereo/_descriptor_core.py +207 -0
- synkit/Graph/Stereo/_descriptor_serialization.py +138 -0
- synkit/Graph/Stereo/canonical.py +648 -0
- synkit/Graph/Stereo/changes.py +964 -0
- synkit/Graph/Stereo/composition.py +391 -0
- synkit/Graph/Stereo/configured.py +946 -0
- synkit/Graph/Stereo/couplings.py +245 -0
- synkit/Graph/Stereo/descriptors.py +1030 -0
- synkit/Graph/Stereo/enumeration.py +597 -0
- synkit/Graph/Stereo/extended_descriptors.py +406 -0
- synkit/Graph/Stereo/global_configured.py +152 -0
- synkit/Graph/Stereo/global_stereo.py +304 -0
- synkit/Graph/Stereo/identity.py +648 -0
- synkit/Graph/Stereo/interchange.py +496 -0
- synkit/Graph/Stereo/legacy.py +460 -0
- synkit/Graph/Stereo/matching.py +899 -0
- synkit/Graph/Stereo/native.py +154 -0
- synkit/Graph/Stereo/orbits.py +668 -0
- synkit/Graph/Stereo/outcomes.py +99 -0
- synkit/Graph/Stereo/pairwise.py +350 -0
- synkit/Graph/Stereo/rdkit_adapter.py +662 -0
- synkit/Graph/Stereo/rdkit_identity.py +118 -0
- synkit/Graph/Stereo/rdkit_resonance.py +140 -0
- synkit/Graph/Stereo/reaction_interchange.py +266 -0
- synkit/Graph/Stereo/semantics.py +296 -0
- synkit/Graph/Stereo/supports.py +257 -0
- synkit/Graph/Stereo/wire.py +339 -0
- synkit/Graph/Wildcard/__init__.py +0 -0
- synkit/Graph/Wildcard/fuse_graph.py +156 -0
- synkit/Graph/Wildcard/graph_wc.py +303 -0
- synkit/Graph/Wildcard/its_merge.py +857 -0
- synkit/Graph/Wildcard/radwc.py +114 -0
- synkit/Graph/Wildcard/wc_matcher.py +576 -0
- synkit/Graph/Wildcard/wildcard.py +225 -0
- synkit/Graph/__init__.py +17 -0
- synkit/Graph/canon_graph.py +14 -0
- synkit/Graph/syn_graph.py +199 -0
- synkit/Graph/utils.py +324 -0
- synkit/IO/__init__.py +4 -0
- synkit/IO/chem_converter.py +1059 -0
- synkit/IO/combinatorial/__init__.py +8 -0
- synkit/IO/combinatorial/gml_to_graph.py +223 -0
- synkit/IO/combinatorial/graph_to_gml.py +280 -0
- synkit/IO/combinatorial/graph_to_smarts.py +186 -0
- synkit/IO/combinatorial/smarts_expander.py +147 -0
- synkit/IO/combinatorial/smarts_generalizer.py +133 -0
- synkit/IO/combinatorial/smarts_to_graph.py +179 -0
- synkit/IO/conversion.py +42 -0
- synkit/IO/data_io.py +269 -0
- synkit/IO/data_process.py +143 -0
- synkit/IO/debug.py +73 -0
- synkit/IO/gml_to_nx.py +150 -0
- synkit/IO/graph_to_mol.py +199 -0
- synkit/IO/mol_to_graph.py +1105 -0
- synkit/IO/mol_to_graph_chemistry.py +545 -0
- synkit/IO/nx_to_gml.py +209 -0
- synkit/IO/smiles_to_id.py +123 -0
- synkit/Mechanism/__init__.py +151 -0
- synkit/Mechanism/adapters.py +136 -0
- synkit/Mechanism/audit.py +323 -0
- synkit/Mechanism/benchmark.py +638 -0
- synkit/Mechanism/compatibility.py +13 -0
- synkit/Mechanism/drawing.py +85 -0
- synkit/Mechanism/electron_models.py +725 -0
- synkit/Mechanism/equivalence.py +521 -0
- synkit/Mechanism/evidence.py +262 -0
- synkit/Mechanism/interchange.py +141 -0
- synkit/Mechanism/model.py +918 -0
- synkit/Mechanism/neighbor_stereo.py +312 -0
- synkit/Mechanism/radical_data.py +740 -0
- synkit/Mechanism/replay.py +986 -0
- synkit/Mechanism/schema.py +264 -0
- synkit/Mechanism/stereo_state.py +416 -0
- synkit/Mechanism/symbols.py +91 -0
- synkit/Rule/Apply/__init__.py +35 -0
- synkit/Rule/Apply/conditions.py +45 -0
- synkit/Rule/Apply/dpo.py +998 -0
- synkit/Rule/Apply/rule_matcher.py +218 -0
- synkit/Rule/Apply/validation.py +354 -0
- synkit/Rule/Compose/__init__.py +106 -0
- synkit/Rule/Compose/_identity.py +43 -0
- synkit/Rule/Compose/composition.py +976 -0
- synkit/Rule/Compose/laws.py +439 -0
- synkit/Rule/Compose/search.py +771 -0
- synkit/Rule/Compose/synrule.py +170 -0
- synkit/Rule/Modify/__init__.py +0 -0
- synkit/Rule/Modify/implict_rule.py +56 -0
- synkit/Rule/Modify/longest_path.py +92 -0
- synkit/Rule/Modify/molecule_rule.py +115 -0
- synkit/Rule/Modify/prune_templates.py +78 -0
- synkit/Rule/Modify/rule_utils.py +194 -0
- synkit/Rule/Modify/strip_rule.py +97 -0
- synkit/Rule/__init__.py +28 -0
- synkit/Rule/generic_stereo.py +884 -0
- synkit/Rule/stereo_identity.py +271 -0
- synkit/Rule/syn_rule.py +1090 -0
- synkit/Synthesis/MSR/__init__.py +0 -0
- synkit/Synthesis/MSR/path_finder.py +239 -0
- synkit/Synthesis/Metrics/__init__.py +0 -0
- synkit/Synthesis/Metrics/_base.py +52 -0
- synkit/Synthesis/Metrics/_plot.py +129 -0
- synkit/Synthesis/Metrics/_ranking.py +179 -0
- synkit/Synthesis/RBL/__init__.py +80 -0
- synkit/Synthesis/RBL/engine.py +1249 -0
- synkit/Synthesis/RBL/matching.py +652 -0
- synkit/Synthesis/RBL/overlap.py +336 -0
- synkit/Synthesis/RBL/pipeline.py +376 -0
- synkit/Synthesis/RBL/policy.py +139 -0
- synkit/Synthesis/RBL/proof.py +370 -0
- synkit/Synthesis/RBL/reaction.py +506 -0
- synkit/Synthesis/RBL/state.py +169 -0
- synkit/Synthesis/RBL/validation.py +1060 -0
- synkit/Synthesis/Reactor/__init__.py +60 -0
- synkit/Synthesis/Reactor/core/__init__.py +1 -0
- synkit/Synthesis/Reactor/core/engine.py +967 -0
- synkit/Synthesis/Reactor/core/product.py +621 -0
- synkit/Synthesis/Reactor/core/rewrite.py +561 -0
- synkit/Synthesis/Reactor/core/strategy.py +44 -0
- synkit/Synthesis/Reactor/matching/__init__.py +1 -0
- synkit/Synthesis/Reactor/matching/mixin.py +920 -0
- synkit/Synthesis/Reactor/matching/policy.py +345 -0
- synkit/Synthesis/Reactor/matching/symmetry.py +309 -0
- synkit/Synthesis/Reactor/output/__init__.py +1 -0
- synkit/Synthesis/Reactor/output/deduplication.py +703 -0
- synkit/Synthesis/Reactor/output/policy.py +16 -0
- synkit/Synthesis/Reactor/output/serialization.py +485 -0
- synkit/Synthesis/Reactor/output/structural.py +893 -0
- synkit/Synthesis/Reactor/stereo/__init__.py +1 -0
- synkit/Synthesis/Reactor/stereo/assignment.py +35 -0
- synkit/Synthesis/Reactor/stereo/mixin.py +780 -0
- synkit/Synthesis/Reactor/variants/__init__.py +1 -0
- synkit/Synthesis/Reactor/variants/imbalanced.py +180 -0
- synkit/Synthesis/Reactor/variants/partial.py +84 -0
- synkit/Synthesis/Reactor/workflow/__init__.py +1 -0
- synkit/Synthesis/Reactor/workflow/batch.py +550 -0
- synkit/Synthesis/Reactor/workflow/benchmark.py +143 -0
- synkit/Synthesis/Reactor/workflow/postprocess.py +267 -0
- synkit/Synthesis/Reactor/workflow/rule_filter.py +210 -0
- synkit/Synthesis/__init__.py +0 -0
- synkit/Synthesis/reactor_utils.py +316 -0
- synkit/Utils/__init__.py +0 -0
- synkit/Utils/utils.py +172 -0
- synkit/Vis/__init__.py +91 -0
- synkit/Vis/crn/__init__.py +40 -0
- synkit/Vis/epd/__init__.py +20 -0
- synkit/Vis/epd/arrows.py +425 -0
- synkit/Vis/epd/chem.py +197 -0
- synkit/Vis/epd/constants.py +83 -0
- synkit/Vis/epd/layout.py +283 -0
- synkit/Vis/epd/mapping.py +51 -0
- synkit/Vis/epd/models.py +136 -0
- synkit/Vis/epd/render.py +543 -0
- synkit/Vis/epd/utils.py +108 -0
- synkit/Vis/epd/visualizer.py +811 -0
- synkit/Vis/graph_visualizer.py +375 -0
- synkit/Vis/its/__init__.py +19 -0
- synkit/Vis/its/drawer.py +615 -0
- synkit/Vis/its_drawer.py +35 -0
- synkit/Vis/molecule/__init__.py +31 -0
- synkit/Vis/molecule/drawer.py +563 -0
- synkit/Vis/molecule/reaction.py +285 -0
- synkit/Vis/molecule_drawer.py +33 -0
- synkit/Vis/mtg/__init__.py +17 -0
- synkit/Vis/mtg/drawer.py +769 -0
- synkit/Vis/mtg_drawer.py +34 -0
- synkit/Vis/pdf_writer.py +146 -0
- synkit/Vis/reaction/__init__.py +19 -0
- synkit/Vis/reaction/rule.py +141 -0
- synkit/Vis/reaction/rxn.py +532 -0
- synkit/Vis/reaction_drawer.py +41 -0
- synkit/Vis/space/__init__.py +17 -0
- synkit/Vis/space/chemical.py +80 -0
- synkit/Vis/space/embedding.py +87 -0
- synkit/Vis/vis_synedu/Vis/__init__.py +7 -0
- synkit/Vis/vis_synedu/Vis/dpo.py +862 -0
- synkit/Vis/vis_synedu/rxn_vis.py +377 -0
- synkit/Vis/vis_synedu/vis.py +501 -0
- synkit/Vis/visual_drawer.py +215 -0
- synkit/Vis/visual_model.py +520 -0
- synkit/__init__.py +3 -0
- synkit/_native.py +91 -0
- synkit/examples.py +50 -0
- synkit/version.py +23 -0
- synkit-1.6.5.dist-info/METADATA +156 -0
- synkit-1.6.5.dist-info/RECORD +636 -0
- synkit-1.6.5.dist-info/WHEEL +4 -0
- synkit-1.6.5.dist-info/licenses/LICENSE +21 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
|
@@ -0,0 +1,995 @@
|
|
|
1
|
+
import networkx as nx
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from copy import copy
|
|
4
|
+
from joblib import Parallel, delayed
|
|
5
|
+
from typing import (
|
|
6
|
+
Any,
|
|
7
|
+
Dict,
|
|
8
|
+
List,
|
|
9
|
+
Tuple,
|
|
10
|
+
Iterable,
|
|
11
|
+
Optional,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from synkit.IO.debug import setup_logging
|
|
15
|
+
from synkit.IO.chem_converter import detect_its_format
|
|
16
|
+
from synkit.Graph.ITS.its_construction import ITSConstruction
|
|
17
|
+
from synkit.Graph.ITS.its_decompose import get_rc, its_decompose
|
|
18
|
+
from synkit.Graph.ITS.its_reverter import ITSReverter
|
|
19
|
+
from synkit.Graph.ITS.rc_extractor import RCExtractor
|
|
20
|
+
from synkit.Graph.Hyrogen._misc import (
|
|
21
|
+
check_hcount_change,
|
|
22
|
+
get_priority,
|
|
23
|
+
)
|
|
24
|
+
from synkit.Graph.Hyrogen.hcompletion_algorithms import (
|
|
25
|
+
HydrogenCompletionAlgorithms,
|
|
26
|
+
ITSFormat,
|
|
27
|
+
ITSFormatInput,
|
|
28
|
+
_HydrogenTransferPlan,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
logger = setup_logging()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class HCompletionResult:
|
|
36
|
+
"""Container returned by graph-first hydrogen completion."""
|
|
37
|
+
|
|
38
|
+
its: Optional[nx.Graph]
|
|
39
|
+
rc: Optional[nx.Graph]
|
|
40
|
+
reactant: Optional[nx.Graph] = None
|
|
41
|
+
product: Optional[nx.Graph] = None
|
|
42
|
+
signature: Optional[str] = None
|
|
43
|
+
candidates: int = 0
|
|
44
|
+
reason: str = ""
|
|
45
|
+
format: str = "typesGH"
|
|
46
|
+
exhaustive: bool = True
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def ok(self) -> bool:
|
|
50
|
+
return (
|
|
51
|
+
isinstance(self.its, nx.Graph)
|
|
52
|
+
and isinstance(self.rc, nx.Graph)
|
|
53
|
+
and self.rc.number_of_nodes() > 0
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class HComplete(HydrogenCompletionAlgorithms):
|
|
58
|
+
"""Complete reaction-centre hydrogens in ITS graphs."""
|
|
59
|
+
|
|
60
|
+
TUPLE_NODE_ATTRS = [
|
|
61
|
+
"element",
|
|
62
|
+
"aromatic",
|
|
63
|
+
"hcount",
|
|
64
|
+
"charge",
|
|
65
|
+
"atom_map",
|
|
66
|
+
"lone_pairs",
|
|
67
|
+
"radical",
|
|
68
|
+
"valence_electrons",
|
|
69
|
+
]
|
|
70
|
+
TUPLE_EDGE_ATTRS = [
|
|
71
|
+
"order",
|
|
72
|
+
"kekule_order",
|
|
73
|
+
"sigma_order",
|
|
74
|
+
"pi_order",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def process_single_graph_data(
|
|
79
|
+
graph_data: Dict[str, nx.Graph],
|
|
80
|
+
its_key: str = "ITS",
|
|
81
|
+
rc_key: str = "RC",
|
|
82
|
+
ignore_aromaticity: bool = False,
|
|
83
|
+
balance_its: bool = True,
|
|
84
|
+
get_priority_graph: bool = False,
|
|
85
|
+
max_hydrogen: int = 7,
|
|
86
|
+
format: ITSFormatInput = "auto",
|
|
87
|
+
max_candidates: Optional[int] = None,
|
|
88
|
+
) -> Dict[str, Optional[nx.Graph]]:
|
|
89
|
+
"""Processes a single graph data dictionary by modifying hydrogen
|
|
90
|
+
counts and other features based on configuration settings.
|
|
91
|
+
|
|
92
|
+
:param graph_data: Dictionary containing the graph data.
|
|
93
|
+
:type graph_data: Dict[str, nx.Graph]
|
|
94
|
+
:param its_key: Key where the ITS graph is stored.
|
|
95
|
+
:type its_key: str
|
|
96
|
+
:param rc_key: Key where the RC graph is stored.
|
|
97
|
+
:type rc_key: str
|
|
98
|
+
:param ignore_aromaticity: If True, aromaticity is ignored during processing. Default is False.
|
|
99
|
+
:type ignore_aromaticity: bool
|
|
100
|
+
:param balance_its: If True, the ITS is balanced. Default is True.
|
|
101
|
+
:type balance_its: bool
|
|
102
|
+
:param get_priority_graph: If True, priority is given to graph data during processing. Default is False.
|
|
103
|
+
:type get_priority_graph: bool
|
|
104
|
+
:param max_hydrogen: Maximum number of hydrogens that can be handled in the inference step.
|
|
105
|
+
:type max_hydrogen: int
|
|
106
|
+
:param format: ITS representation: "auto", "typesGH", or "tuple".
|
|
107
|
+
:type format: str
|
|
108
|
+
:param max_candidates: Optional cap for enumerated hydrogen assignments.
|
|
109
|
+
:type max_candidates: Optional[int]
|
|
110
|
+
|
|
111
|
+
:return: Dictionary with updated ITS and RC graph data, or None if processing fails.
|
|
112
|
+
:rtype: Dict[str, Optional[nx.Graph]]
|
|
113
|
+
"""
|
|
114
|
+
graphs = copy(graph_data)
|
|
115
|
+
its = graphs.get(its_key, None)
|
|
116
|
+
result = HComplete.complete_its(
|
|
117
|
+
its,
|
|
118
|
+
ignore_aromaticity=ignore_aromaticity,
|
|
119
|
+
balance_its=balance_its,
|
|
120
|
+
get_priority_graph=get_priority_graph,
|
|
121
|
+
max_hydrogen=max_hydrogen,
|
|
122
|
+
format=format,
|
|
123
|
+
max_candidates=max_candidates,
|
|
124
|
+
)
|
|
125
|
+
graphs[its_key] = result.its if result.ok else None
|
|
126
|
+
graphs[rc_key] = result.rc if result.ok else None
|
|
127
|
+
return graphs
|
|
128
|
+
|
|
129
|
+
def process_graph_data_parallel(
|
|
130
|
+
self,
|
|
131
|
+
graph_data_list: List[Dict[str, nx.Graph]],
|
|
132
|
+
its_key: str = "ITS",
|
|
133
|
+
rc_key: str = "RC",
|
|
134
|
+
n_jobs: int = 1,
|
|
135
|
+
verbose: int = 0,
|
|
136
|
+
ignore_aromaticity: bool = False,
|
|
137
|
+
balance_its: bool = True,
|
|
138
|
+
get_priority_graph: bool = False,
|
|
139
|
+
max_hydrogen: int = 7,
|
|
140
|
+
format: ITSFormatInput = "auto",
|
|
141
|
+
max_candidates: Optional[int] = None,
|
|
142
|
+
) -> List[Dict[str, Optional[nx.Graph]]]:
|
|
143
|
+
"""Processes a list of graph data dictionaries in parallel to optimize
|
|
144
|
+
the hydrogen completion and other graph modifications.
|
|
145
|
+
|
|
146
|
+
:param graph_data_list: List of dictionaries containing the graph data.
|
|
147
|
+
:type graph_data_list: List[Dict[str, nx.Graph]]
|
|
148
|
+
:param its_key: Key where the ITS graph is stored.
|
|
149
|
+
:type its_key: str
|
|
150
|
+
:param rc_key: Key where the RC graph is stored.
|
|
151
|
+
:type rc_key: str
|
|
152
|
+
:param n_jobs: Number of parallel jobs to run.
|
|
153
|
+
:type n_jobs: int
|
|
154
|
+
:param verbose: Verbosity level for the parallel process.
|
|
155
|
+
:type verbose: int
|
|
156
|
+
:param ignore_aromaticity: If True, aromaticity is ignored during processing. Default is False.
|
|
157
|
+
:type ignore_aromaticity: bool
|
|
158
|
+
:param balance_its: If True, the ITS is balanced. Default is True.
|
|
159
|
+
:type balance_its: bool
|
|
160
|
+
:param get_priority_graph: If True, priority is given to graph data during processing. Default is False.
|
|
161
|
+
:type get_priority_graph: bool
|
|
162
|
+
:param max_hydrogen: Maximum number of hydrogens that can be handled in the inference step.
|
|
163
|
+
:type max_hydrogen: int
|
|
164
|
+
:param format: ITS representation: "auto", "typesGH", or "tuple".
|
|
165
|
+
:type format: str
|
|
166
|
+
:param max_candidates: Optional cap for enumerated hydrogen assignments.
|
|
167
|
+
:type max_candidates: Optional[int]
|
|
168
|
+
|
|
169
|
+
:return: List of dictionaries with updated ITS and RC graph data, or None if processing fails.
|
|
170
|
+
:rtype: List[Dict[str, Optional[nx.Graph]]]
|
|
171
|
+
"""
|
|
172
|
+
processed_data = Parallel(n_jobs=n_jobs, verbose=verbose)(
|
|
173
|
+
delayed(self.process_single_graph_data)(
|
|
174
|
+
graph_data,
|
|
175
|
+
its_key,
|
|
176
|
+
rc_key,
|
|
177
|
+
ignore_aromaticity,
|
|
178
|
+
balance_its,
|
|
179
|
+
get_priority_graph,
|
|
180
|
+
max_hydrogen,
|
|
181
|
+
format,
|
|
182
|
+
max_candidates,
|
|
183
|
+
)
|
|
184
|
+
for graph_data in graph_data_list
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return processed_data
|
|
188
|
+
|
|
189
|
+
@staticmethod
|
|
190
|
+
def complete_its(
|
|
191
|
+
its: nx.Graph,
|
|
192
|
+
ignore_aromaticity: bool = False,
|
|
193
|
+
balance_its: bool = True,
|
|
194
|
+
get_priority_graph: bool = False,
|
|
195
|
+
max_hydrogen: int = 7,
|
|
196
|
+
format: ITSFormatInput = "auto",
|
|
197
|
+
max_candidates: Optional[int] = None,
|
|
198
|
+
) -> HCompletionResult:
|
|
199
|
+
"""Complete hydrogens for a bare ITS graph.
|
|
200
|
+
|
|
201
|
+
This is the graph-first API. It accepts either legacy ``typesGH`` ITS
|
|
202
|
+
graphs or tuple ITS graphs and returns completed ITS/RC graphs without
|
|
203
|
+
requiring a dictionary entry wrapper.
|
|
204
|
+
"""
|
|
205
|
+
if not isinstance(its, nx.Graph) or its.number_of_nodes() == 0:
|
|
206
|
+
return HCompletionResult(None, None, reason="invalid_its")
|
|
207
|
+
|
|
208
|
+
resolved_format = HComplete._resolve_format(its, format)
|
|
209
|
+
react_graph, prod_graph = HComplete._decompose_its(its, resolved_format)
|
|
210
|
+
hcount_change = check_hcount_change(react_graph, prod_graph)
|
|
211
|
+
|
|
212
|
+
if hcount_change == 0:
|
|
213
|
+
rc = HComplete._extract_rc(its, resolved_format)
|
|
214
|
+
if not HComplete._valid_rc(rc):
|
|
215
|
+
return HCompletionResult(
|
|
216
|
+
None,
|
|
217
|
+
None,
|
|
218
|
+
react_graph,
|
|
219
|
+
prod_graph,
|
|
220
|
+
candidates=1,
|
|
221
|
+
reason="empty_rc",
|
|
222
|
+
format=resolved_format,
|
|
223
|
+
)
|
|
224
|
+
return HCompletionResult(
|
|
225
|
+
its,
|
|
226
|
+
rc,
|
|
227
|
+
react_graph,
|
|
228
|
+
prod_graph,
|
|
229
|
+
signature=HComplete._rc_signature(rc, resolved_format),
|
|
230
|
+
candidates=1,
|
|
231
|
+
format=resolved_format,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
if hcount_change > max_hydrogen:
|
|
235
|
+
return HCompletionResult(
|
|
236
|
+
None,
|
|
237
|
+
None,
|
|
238
|
+
react_graph,
|
|
239
|
+
prod_graph,
|
|
240
|
+
reason="max_hydrogen_exceeded",
|
|
241
|
+
format=resolved_format,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
return HComplete._complete_from_side_graphs(
|
|
245
|
+
react_graph,
|
|
246
|
+
prod_graph,
|
|
247
|
+
ignore_aromaticity=ignore_aromaticity,
|
|
248
|
+
balance_its=balance_its,
|
|
249
|
+
get_priority_graph=get_priority_graph,
|
|
250
|
+
format=resolved_format,
|
|
251
|
+
max_candidates=max_candidates,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
@staticmethod
|
|
255
|
+
def process_multiple_hydrogens(
|
|
256
|
+
graph_data: Dict[str, nx.Graph],
|
|
257
|
+
its_key: str,
|
|
258
|
+
rc_key: str,
|
|
259
|
+
react_graph: nx.Graph,
|
|
260
|
+
prod_graph: nx.Graph,
|
|
261
|
+
ignore_aromaticity: bool,
|
|
262
|
+
balance_its: bool,
|
|
263
|
+
get_priority_graph: bool = False,
|
|
264
|
+
format: ITSFormatInput = "typesGH",
|
|
265
|
+
max_candidates: Optional[int] = None,
|
|
266
|
+
) -> Dict[str, Optional[nx.Graph]]:
|
|
267
|
+
"""Handles significant hydrogen count changes between reactant and
|
|
268
|
+
product graphs, adjusting hydrogen nodes accordingly and assessing
|
|
269
|
+
graph equivalence.
|
|
270
|
+
|
|
271
|
+
:param graph_data: Dictionary containing the graph data.
|
|
272
|
+
:type graph_data: Dict[str, nx.Graph]
|
|
273
|
+
:param its_key: Key for the ITS graph in the dictionary.
|
|
274
|
+
:type its_key: str
|
|
275
|
+
:param rc_key: Key for the RC graph in the dictionary.
|
|
276
|
+
:type rc_key: str
|
|
277
|
+
:param react_graph: Graph representing the reactants.
|
|
278
|
+
:type react_graph: nx.Graph
|
|
279
|
+
:param prod_graph: Graph representing the products.
|
|
280
|
+
:type prod_graph: nx.Graph
|
|
281
|
+
:param ignore_aromaticity: If True, aromaticity will not be considered in processing.
|
|
282
|
+
:type ignore_aromaticity: bool
|
|
283
|
+
:param balance_its: If True, balances the ITS graph.
|
|
284
|
+
:type balance_its: bool
|
|
285
|
+
:param get_priority_graph: If True, processes graphs with priority considerations.
|
|
286
|
+
:type get_priority_graph: bool
|
|
287
|
+
:param format: ITS representation: "auto", "typesGH", or "tuple".
|
|
288
|
+
:type format: str
|
|
289
|
+
:param max_candidates: Optional cap for enumerated hydrogen assignments.
|
|
290
|
+
:type max_candidates: Optional[int]
|
|
291
|
+
|
|
292
|
+
:return: Updated graph dictionary with potentially modified ITS and RC graphs.
|
|
293
|
+
:rtype: Dict[str, Optional[nx.Graph]]
|
|
294
|
+
"""
|
|
295
|
+
result = HComplete._complete_from_side_graphs(
|
|
296
|
+
react_graph,
|
|
297
|
+
prod_graph,
|
|
298
|
+
ignore_aromaticity=ignore_aromaticity,
|
|
299
|
+
balance_its=balance_its,
|
|
300
|
+
get_priority_graph=get_priority_graph,
|
|
301
|
+
format=HComplete._resolve_graph_pair_format(
|
|
302
|
+
react_graph, prod_graph, format
|
|
303
|
+
),
|
|
304
|
+
max_candidates=max_candidates,
|
|
305
|
+
)
|
|
306
|
+
graph_data[its_key] = result.its if result.ok else None
|
|
307
|
+
graph_data[rc_key] = result.rc if result.ok else None
|
|
308
|
+
return graph_data
|
|
309
|
+
|
|
310
|
+
@staticmethod
|
|
311
|
+
def _complete_from_side_graphs(
|
|
312
|
+
react_graph: nx.Graph,
|
|
313
|
+
prod_graph: nx.Graph,
|
|
314
|
+
ignore_aromaticity: bool,
|
|
315
|
+
balance_its: bool,
|
|
316
|
+
get_priority_graph: bool,
|
|
317
|
+
format: ITSFormat,
|
|
318
|
+
max_candidates: Optional[int] = None,
|
|
319
|
+
) -> HCompletionResult:
|
|
320
|
+
if get_priority_graph:
|
|
321
|
+
return HComplete._complete_priority_from_transfer_plans(
|
|
322
|
+
react_graph,
|
|
323
|
+
prod_graph,
|
|
324
|
+
ignore_aromaticity,
|
|
325
|
+
balance_its,
|
|
326
|
+
format,
|
|
327
|
+
max_candidates,
|
|
328
|
+
)
|
|
329
|
+
if format == "typesGH":
|
|
330
|
+
return HComplete._complete_typesgh_from_transfer_plans(
|
|
331
|
+
react_graph,
|
|
332
|
+
prod_graph,
|
|
333
|
+
ignore_aromaticity,
|
|
334
|
+
balance_its,
|
|
335
|
+
max_candidates,
|
|
336
|
+
)
|
|
337
|
+
return HComplete._complete_exact_from_transfer_plans(
|
|
338
|
+
react_graph,
|
|
339
|
+
prod_graph,
|
|
340
|
+
ignore_aromaticity,
|
|
341
|
+
balance_its,
|
|
342
|
+
format,
|
|
343
|
+
max_candidates,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
@staticmethod
|
|
347
|
+
def _complete_typesgh_from_transfer_plans(
|
|
348
|
+
react_graph: nx.Graph,
|
|
349
|
+
prod_graph: nx.Graph,
|
|
350
|
+
ignore_aromaticity: bool,
|
|
351
|
+
balance_its: bool,
|
|
352
|
+
max_candidates: Optional[int],
|
|
353
|
+
) -> HCompletionResult:
|
|
354
|
+
"""Decide typesGH completion using an exact necessary RC projection."""
|
|
355
|
+
first_plan = None
|
|
356
|
+
first_projection = None
|
|
357
|
+
first_candidate = None
|
|
358
|
+
valid_seen = 0
|
|
359
|
+
|
|
360
|
+
for candidate_index, plan in enumerate(
|
|
361
|
+
HComplete._iter_hydrogen_transfer_plans(react_graph, prod_graph)
|
|
362
|
+
):
|
|
363
|
+
if max_candidates is not None and candidate_index >= max_candidates:
|
|
364
|
+
return HComplete._candidate_limit_result(
|
|
365
|
+
react_graph, prod_graph, valid_seen, "typesGH"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
projection = HComplete._typesgh_plan_comparison_graph(
|
|
369
|
+
react_graph,
|
|
370
|
+
prod_graph,
|
|
371
|
+
plan,
|
|
372
|
+
ignore_aromaticity,
|
|
373
|
+
)
|
|
374
|
+
if projection.number_of_nodes() == 0:
|
|
375
|
+
continue
|
|
376
|
+
|
|
377
|
+
valid_seen += 1
|
|
378
|
+
if first_plan is None:
|
|
379
|
+
first_plan = plan
|
|
380
|
+
first_projection = projection
|
|
381
|
+
continue
|
|
382
|
+
|
|
383
|
+
# Full typesGH RC isomorphism preserves this labeled projection.
|
|
384
|
+
# Its non-isomorphism is therefore a conclusive ambiguity witness.
|
|
385
|
+
if not HComplete._comparison_graphs_isomorphic(
|
|
386
|
+
first_projection, projection
|
|
387
|
+
):
|
|
388
|
+
return HCompletionResult(
|
|
389
|
+
None,
|
|
390
|
+
None,
|
|
391
|
+
react_graph,
|
|
392
|
+
prod_graph,
|
|
393
|
+
candidates=valid_seen,
|
|
394
|
+
reason="non_equivariant_rc",
|
|
395
|
+
format="typesGH",
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
if first_candidate is None:
|
|
399
|
+
first_candidate = HComplete._materialize_transfer_candidate(
|
|
400
|
+
react_graph,
|
|
401
|
+
prod_graph,
|
|
402
|
+
first_plan,
|
|
403
|
+
ignore_aromaticity,
|
|
404
|
+
balance_its,
|
|
405
|
+
"typesGH",
|
|
406
|
+
)
|
|
407
|
+
if not HComplete._valid_rc(first_candidate[3]):
|
|
408
|
+
first_candidate = None
|
|
409
|
+
continue
|
|
410
|
+
|
|
411
|
+
candidate = HComplete._materialize_transfer_candidate(
|
|
412
|
+
react_graph,
|
|
413
|
+
prod_graph,
|
|
414
|
+
plan,
|
|
415
|
+
ignore_aromaticity,
|
|
416
|
+
balance_its,
|
|
417
|
+
"typesGH",
|
|
418
|
+
)
|
|
419
|
+
if not HComplete._valid_rc(candidate[3]):
|
|
420
|
+
continue
|
|
421
|
+
if (
|
|
422
|
+
HComplete._equivariant_count(
|
|
423
|
+
[first_candidate[3], candidate[3]], "typesGH"
|
|
424
|
+
)
|
|
425
|
+
!= 1
|
|
426
|
+
):
|
|
427
|
+
return HCompletionResult(
|
|
428
|
+
None,
|
|
429
|
+
None,
|
|
430
|
+
react_graph,
|
|
431
|
+
prod_graph,
|
|
432
|
+
candidates=valid_seen,
|
|
433
|
+
reason="non_equivariant_rc",
|
|
434
|
+
format="typesGH",
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
if first_plan is None:
|
|
438
|
+
return HCompletionResult(
|
|
439
|
+
None,
|
|
440
|
+
None,
|
|
441
|
+
react_graph,
|
|
442
|
+
prod_graph,
|
|
443
|
+
candidates=valid_seen,
|
|
444
|
+
reason="no_valid_candidate",
|
|
445
|
+
format="typesGH",
|
|
446
|
+
)
|
|
447
|
+
if first_candidate is None:
|
|
448
|
+
first_candidate = HComplete._materialize_transfer_candidate(
|
|
449
|
+
react_graph,
|
|
450
|
+
prod_graph,
|
|
451
|
+
first_plan,
|
|
452
|
+
ignore_aromaticity,
|
|
453
|
+
balance_its,
|
|
454
|
+
"typesGH",
|
|
455
|
+
)
|
|
456
|
+
return HComplete._completion_result(
|
|
457
|
+
first_candidate,
|
|
458
|
+
react_graph,
|
|
459
|
+
prod_graph,
|
|
460
|
+
valid_seen,
|
|
461
|
+
"typesGH",
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
@staticmethod
|
|
465
|
+
def _complete_exact_from_transfer_plans(
|
|
466
|
+
react_graph: nx.Graph,
|
|
467
|
+
prod_graph: nx.Graph,
|
|
468
|
+
ignore_aromaticity: bool,
|
|
469
|
+
balance_its: bool,
|
|
470
|
+
format: ITSFormat,
|
|
471
|
+
max_candidates: Optional[int],
|
|
472
|
+
) -> HCompletionResult:
|
|
473
|
+
"""Decide completion solely through materialized exact RC isomorphism."""
|
|
474
|
+
first = None
|
|
475
|
+
valid_seen = 0
|
|
476
|
+
for candidate_index, plan in enumerate(
|
|
477
|
+
HComplete._iter_hydrogen_transfer_plans(react_graph, prod_graph)
|
|
478
|
+
):
|
|
479
|
+
if max_candidates is not None and candidate_index >= max_candidates:
|
|
480
|
+
return HComplete._candidate_limit_result(
|
|
481
|
+
react_graph, prod_graph, valid_seen, format
|
|
482
|
+
)
|
|
483
|
+
candidate = HComplete._materialize_transfer_candidate(
|
|
484
|
+
react_graph,
|
|
485
|
+
prod_graph,
|
|
486
|
+
plan,
|
|
487
|
+
ignore_aromaticity,
|
|
488
|
+
balance_its,
|
|
489
|
+
format,
|
|
490
|
+
)
|
|
491
|
+
if not HComplete._valid_rc(candidate[3]):
|
|
492
|
+
continue
|
|
493
|
+
valid_seen += 1
|
|
494
|
+
if first is None:
|
|
495
|
+
first = candidate
|
|
496
|
+
continue
|
|
497
|
+
if HComplete._equivariant_count([first[3], candidate[3]], format) != 1:
|
|
498
|
+
return HCompletionResult(
|
|
499
|
+
None,
|
|
500
|
+
None,
|
|
501
|
+
react_graph,
|
|
502
|
+
prod_graph,
|
|
503
|
+
candidates=valid_seen,
|
|
504
|
+
reason="non_equivariant_rc",
|
|
505
|
+
format=format,
|
|
506
|
+
)
|
|
507
|
+
return HComplete._completion_result(
|
|
508
|
+
first,
|
|
509
|
+
react_graph,
|
|
510
|
+
prod_graph,
|
|
511
|
+
valid_seen,
|
|
512
|
+
format,
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
@staticmethod
|
|
516
|
+
def _complete_priority_from_transfer_plans(
|
|
517
|
+
react_graph: nx.Graph,
|
|
518
|
+
prod_graph: nx.Graph,
|
|
519
|
+
ignore_aromaticity: bool,
|
|
520
|
+
balance_its: bool,
|
|
521
|
+
format: ITSFormat,
|
|
522
|
+
max_candidates: Optional[int],
|
|
523
|
+
) -> HCompletionResult:
|
|
524
|
+
candidates = []
|
|
525
|
+
valid_seen = 0
|
|
526
|
+
for candidate_index, plan in enumerate(
|
|
527
|
+
HComplete._iter_hydrogen_transfer_plans(react_graph, prod_graph)
|
|
528
|
+
):
|
|
529
|
+
if max_candidates is not None and candidate_index >= max_candidates:
|
|
530
|
+
return HComplete._candidate_limit_result(
|
|
531
|
+
react_graph, prod_graph, valid_seen, format
|
|
532
|
+
)
|
|
533
|
+
candidate = HComplete._materialize_transfer_candidate(
|
|
534
|
+
react_graph,
|
|
535
|
+
prod_graph,
|
|
536
|
+
plan,
|
|
537
|
+
ignore_aromaticity,
|
|
538
|
+
balance_its,
|
|
539
|
+
format,
|
|
540
|
+
)
|
|
541
|
+
if not HComplete._valid_rc(candidate[3]):
|
|
542
|
+
continue
|
|
543
|
+
valid_seen += 1
|
|
544
|
+
candidates.append(candidate)
|
|
545
|
+
selected = HComplete._select_priority_candidate(candidates, format)
|
|
546
|
+
return HComplete._completion_result(
|
|
547
|
+
selected,
|
|
548
|
+
react_graph,
|
|
549
|
+
prod_graph,
|
|
550
|
+
valid_seen,
|
|
551
|
+
format,
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
@staticmethod
|
|
555
|
+
def _materialize_transfer_candidate(
|
|
556
|
+
react_graph: nx.Graph,
|
|
557
|
+
prod_graph: nx.Graph,
|
|
558
|
+
plan: _HydrogenTransferPlan,
|
|
559
|
+
ignore_aromaticity: bool,
|
|
560
|
+
balance_its: bool,
|
|
561
|
+
format: ITSFormat,
|
|
562
|
+
) -> Tuple[nx.Graph, nx.Graph, nx.Graph, nx.Graph, str]:
|
|
563
|
+
react, prod = HComplete._realize_hydrogen_transfer_plan(
|
|
564
|
+
react_graph, prod_graph, plan
|
|
565
|
+
)
|
|
566
|
+
its = HComplete._construct_its(
|
|
567
|
+
react,
|
|
568
|
+
prod,
|
|
569
|
+
ignore_aromaticity,
|
|
570
|
+
balance_its,
|
|
571
|
+
format,
|
|
572
|
+
)
|
|
573
|
+
rc = HComplete._extract_rc(its, format)
|
|
574
|
+
signature = HComplete._rc_signature(rc, format)
|
|
575
|
+
return react, prod, its, rc, signature
|
|
576
|
+
|
|
577
|
+
@staticmethod
|
|
578
|
+
def _candidate_limit_result(
|
|
579
|
+
react_graph: nx.Graph,
|
|
580
|
+
prod_graph: nx.Graph,
|
|
581
|
+
candidates: int,
|
|
582
|
+
format: ITSFormat,
|
|
583
|
+
) -> HCompletionResult:
|
|
584
|
+
return HCompletionResult(
|
|
585
|
+
None,
|
|
586
|
+
None,
|
|
587
|
+
react_graph,
|
|
588
|
+
prod_graph,
|
|
589
|
+
candidates=candidates,
|
|
590
|
+
reason="max_candidates_reached",
|
|
591
|
+
format=format,
|
|
592
|
+
exhaustive=False,
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
@staticmethod
|
|
596
|
+
def _completion_result(
|
|
597
|
+
selected: Optional[Tuple[nx.Graph, nx.Graph, nx.Graph, nx.Graph, str]],
|
|
598
|
+
react_graph: nx.Graph,
|
|
599
|
+
prod_graph: nx.Graph,
|
|
600
|
+
candidates: int,
|
|
601
|
+
format: ITSFormat,
|
|
602
|
+
) -> HCompletionResult:
|
|
603
|
+
if selected is None or not HComplete._valid_rc(selected[3]):
|
|
604
|
+
return HCompletionResult(
|
|
605
|
+
None,
|
|
606
|
+
None,
|
|
607
|
+
react_graph,
|
|
608
|
+
prod_graph,
|
|
609
|
+
candidates=candidates,
|
|
610
|
+
reason="no_valid_candidate",
|
|
611
|
+
format=format,
|
|
612
|
+
)
|
|
613
|
+
react, prod, its, rc, sig = selected
|
|
614
|
+
return HCompletionResult(
|
|
615
|
+
its,
|
|
616
|
+
rc,
|
|
617
|
+
react,
|
|
618
|
+
prod,
|
|
619
|
+
signature=sig,
|
|
620
|
+
candidates=candidates,
|
|
621
|
+
format=format,
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
@staticmethod
|
|
625
|
+
def _select_priority_candidate(
|
|
626
|
+
candidates: List[Tuple[nx.Graph, nx.Graph, nx.Graph, nx.Graph, str]],
|
|
627
|
+
format: ITSFormat,
|
|
628
|
+
) -> Optional[Tuple[nx.Graph, nx.Graph, nx.Graph, nx.Graph, str]]:
|
|
629
|
+
if not candidates:
|
|
630
|
+
return None
|
|
631
|
+
|
|
632
|
+
rc_list = [candidate[3] for candidate in candidates]
|
|
633
|
+
rc_sig = [candidate[4] for candidate in candidates]
|
|
634
|
+
|
|
635
|
+
if len(set(rc_sig)) == 1:
|
|
636
|
+
equivariant = HComplete._equivariant_count(rc_list, format)
|
|
637
|
+
else:
|
|
638
|
+
equivariant = 0
|
|
639
|
+
|
|
640
|
+
if equivariant == len(rc_list) - 1:
|
|
641
|
+
return candidates[0]
|
|
642
|
+
|
|
643
|
+
priority_indices = get_priority(rc_list)
|
|
644
|
+
priority_candidates = [candidates[i] for i in priority_indices]
|
|
645
|
+
priority_rc = [candidate[3] for candidate in priority_candidates]
|
|
646
|
+
priority_sig = [candidate[4] for candidate in priority_candidates]
|
|
647
|
+
|
|
648
|
+
if len(set(priority_sig)) == 1:
|
|
649
|
+
equivariant = HComplete._equivariant_count(priority_rc, format)
|
|
650
|
+
if equivariant == len(priority_rc) - 1:
|
|
651
|
+
return priority_candidates[0]
|
|
652
|
+
return None
|
|
653
|
+
|
|
654
|
+
@staticmethod
|
|
655
|
+
def add_hydrogen_nodes_multiple(
|
|
656
|
+
react_graph: nx.Graph,
|
|
657
|
+
prod_graph: nx.Graph,
|
|
658
|
+
ignore_aromaticity: bool,
|
|
659
|
+
balance_its: bool,
|
|
660
|
+
get_priority_graph: bool = False,
|
|
661
|
+
format: ITSFormatInput = "typesGH",
|
|
662
|
+
max_candidates: Optional[int] = None,
|
|
663
|
+
) -> List[Tuple[nx.Graph, nx.Graph, nx.Graph, nx.Graph, str]]:
|
|
664
|
+
"""Generates multiple permutations of reactant and product graphs by
|
|
665
|
+
adjusting hydrogen counts, exploring all possible configurations of
|
|
666
|
+
hydrogen node additions or removals.
|
|
667
|
+
|
|
668
|
+
:param react_graph: The reactant graph.
|
|
669
|
+
:type react_graph: nx.Graph
|
|
670
|
+
:param prod_graph: The product graph.
|
|
671
|
+
:type prod_graph: nx.Graph
|
|
672
|
+
:param ignore_aromaticity: If True, aromaticity is ignored.
|
|
673
|
+
:type ignore_aromaticity: bool
|
|
674
|
+
:param balance_its: If True, attempts to balance the ITS by adjusting hydrogen nodes.
|
|
675
|
+
:type balance_its: bool
|
|
676
|
+
:param get_priority_graph: If True, additional priority-based processing
|
|
677
|
+
is applied to select optimal graph configurations.
|
|
678
|
+
:type get_priority_graph: bool
|
|
679
|
+
:param format: ITS representation: "auto", "typesGH", or "tuple".
|
|
680
|
+
:type format: str
|
|
681
|
+
:param max_candidates: Optional cap for enumerated hydrogen assignments.
|
|
682
|
+
:type max_candidates: Optional[int]
|
|
683
|
+
|
|
684
|
+
:return: Candidate reactant, product, ITS, RC, and RC-signature tuples.
|
|
685
|
+
:rtype: List[Tuple[nx.Graph, nx.Graph, nx.Graph, nx.Graph, str]]
|
|
686
|
+
"""
|
|
687
|
+
resolved_format = HComplete._resolve_graph_pair_format(
|
|
688
|
+
react_graph, prod_graph, format
|
|
689
|
+
)
|
|
690
|
+
updated_graphs = []
|
|
691
|
+
|
|
692
|
+
for candidate in HComplete._iter_hydrogen_node_completions(
|
|
693
|
+
react_graph,
|
|
694
|
+
prod_graph,
|
|
695
|
+
ignore_aromaticity,
|
|
696
|
+
balance_its,
|
|
697
|
+
format=resolved_format,
|
|
698
|
+
max_candidates=max_candidates,
|
|
699
|
+
):
|
|
700
|
+
if get_priority_graph is False and updated_graphs:
|
|
701
|
+
previous = updated_graphs[-1]
|
|
702
|
+
if (
|
|
703
|
+
candidate[-1] != previous[-1]
|
|
704
|
+
or HComplete._equivariant_count(
|
|
705
|
+
[previous[3], candidate[3]], resolved_format
|
|
706
|
+
)
|
|
707
|
+
!= 1
|
|
708
|
+
):
|
|
709
|
+
return []
|
|
710
|
+
updated_graphs.append(candidate)
|
|
711
|
+
return updated_graphs
|
|
712
|
+
|
|
713
|
+
@staticmethod
|
|
714
|
+
def _hcount_change_atoms(
|
|
715
|
+
react_graph: nx.Graph,
|
|
716
|
+
prod_graph: nx.Graph,
|
|
717
|
+
) -> Tuple[List[int], List[int]]:
|
|
718
|
+
hydrogen_nodes_break: List[int] = []
|
|
719
|
+
hydrogen_nodes_form: List[int] = []
|
|
720
|
+
|
|
721
|
+
for node_id in sorted(set(react_graph.nodes) & set(prod_graph.nodes)):
|
|
722
|
+
react_hcount = react_graph.nodes[node_id].get("hcount", 0)
|
|
723
|
+
prod_hcount = prod_graph.nodes[node_id].get("hcount", 0)
|
|
724
|
+
hcount_diff = react_hcount - prod_hcount
|
|
725
|
+
|
|
726
|
+
if hcount_diff > 0:
|
|
727
|
+
hydrogen_nodes_break.extend([node_id] * hcount_diff)
|
|
728
|
+
elif hcount_diff < 0:
|
|
729
|
+
hydrogen_nodes_form.extend([node_id] * -hcount_diff)
|
|
730
|
+
|
|
731
|
+
return hydrogen_nodes_break, hydrogen_nodes_form
|
|
732
|
+
|
|
733
|
+
@staticmethod
|
|
734
|
+
def _resolve_format(its: nx.Graph, format: ITSFormatInput) -> ITSFormat:
|
|
735
|
+
if format == "auto":
|
|
736
|
+
return detect_its_format(its)
|
|
737
|
+
if format in ("typesGH", "tuple"):
|
|
738
|
+
return format
|
|
739
|
+
raise ValueError("format must be one of 'auto', 'typesGH', or 'tuple'.")
|
|
740
|
+
|
|
741
|
+
@staticmethod
|
|
742
|
+
def _resolve_graph_pair_format(
|
|
743
|
+
react_graph: nx.Graph,
|
|
744
|
+
prod_graph: nx.Graph,
|
|
745
|
+
format: ITSFormatInput,
|
|
746
|
+
) -> ITSFormat:
|
|
747
|
+
if format == "auto":
|
|
748
|
+
return "typesGH"
|
|
749
|
+
if format in ("typesGH", "tuple"):
|
|
750
|
+
return format
|
|
751
|
+
raise ValueError("format must be one of 'auto', 'typesGH', or 'tuple'.")
|
|
752
|
+
|
|
753
|
+
@staticmethod
|
|
754
|
+
def _decompose_its(its: nx.Graph, format: ITSFormat) -> Tuple[nx.Graph, nx.Graph]:
|
|
755
|
+
if format == "typesGH":
|
|
756
|
+
return its_decompose(its)
|
|
757
|
+
|
|
758
|
+
reverter = ITSReverter(its)
|
|
759
|
+
return reverter.to_reactant_graph(), reverter.to_product_graph()
|
|
760
|
+
|
|
761
|
+
@staticmethod
|
|
762
|
+
def _construct_its(
|
|
763
|
+
react_graph: nx.Graph,
|
|
764
|
+
prod_graph: nx.Graph,
|
|
765
|
+
ignore_aromaticity: bool,
|
|
766
|
+
balance_its: bool,
|
|
767
|
+
format: ITSFormat,
|
|
768
|
+
) -> nx.Graph:
|
|
769
|
+
if format == "typesGH":
|
|
770
|
+
return ITSConstruction().ITSGraph(
|
|
771
|
+
react_graph,
|
|
772
|
+
prod_graph,
|
|
773
|
+
ignore_aromaticity=ignore_aromaticity,
|
|
774
|
+
balance_its=balance_its,
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
return ITSConstruction.construct(
|
|
778
|
+
react_graph,
|
|
779
|
+
prod_graph,
|
|
780
|
+
ignore_aromaticity=ignore_aromaticity,
|
|
781
|
+
balance_its=balance_its,
|
|
782
|
+
store=True,
|
|
783
|
+
node_attrs=HComplete.TUPLE_NODE_ATTRS,
|
|
784
|
+
edge_attrs=HComplete.TUPLE_EDGE_ATTRS,
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
@staticmethod
|
|
788
|
+
def _extract_rc(its: nx.Graph, format: ITSFormat) -> nx.Graph:
|
|
789
|
+
if format == "typesGH":
|
|
790
|
+
return get_rc(its)
|
|
791
|
+
return RCExtractor(preserve_full_attrs=True).extract(its)
|
|
792
|
+
|
|
793
|
+
@staticmethod
|
|
794
|
+
def _valid_rc(rc: Optional[nx.Graph]) -> bool:
|
|
795
|
+
return isinstance(rc, nx.Graph) and rc.number_of_nodes() > 0
|
|
796
|
+
|
|
797
|
+
@staticmethod
|
|
798
|
+
def _candidate_edge_keys(
|
|
799
|
+
react_graph: nx.Graph, prod_graph: nx.Graph
|
|
800
|
+
) -> List[Tuple[int, int]]:
|
|
801
|
+
edge_keys = {tuple(sorted(edge)) for edge in react_graph.edges}
|
|
802
|
+
edge_keys.update(tuple(sorted(edge)) for edge in prod_graph.edges)
|
|
803
|
+
return sorted(edge_keys)
|
|
804
|
+
|
|
805
|
+
@staticmethod
|
|
806
|
+
def _candidate_edge_order_pair(
|
|
807
|
+
react_graph: nx.Graph,
|
|
808
|
+
prod_graph: nx.Graph,
|
|
809
|
+
u: int,
|
|
810
|
+
v: int,
|
|
811
|
+
) -> Tuple[Any, Any]:
|
|
812
|
+
return (
|
|
813
|
+
HComplete._candidate_edge_attr(react_graph, u, v, "order", 0.0),
|
|
814
|
+
HComplete._candidate_edge_attr(prod_graph, u, v, "order", 0.0),
|
|
815
|
+
)
|
|
816
|
+
|
|
817
|
+
@staticmethod
|
|
818
|
+
def _candidate_standard_order(
|
|
819
|
+
react_order: Any,
|
|
820
|
+
prod_order: Any,
|
|
821
|
+
ignore_aromaticity: bool,
|
|
822
|
+
) -> Any:
|
|
823
|
+
try:
|
|
824
|
+
standard_order = react_order - prod_order
|
|
825
|
+
except TypeError:
|
|
826
|
+
return 0
|
|
827
|
+
if ignore_aromaticity and abs(standard_order) < 1:
|
|
828
|
+
return 0
|
|
829
|
+
return standard_order
|
|
830
|
+
|
|
831
|
+
@staticmethod
|
|
832
|
+
def _candidate_typesgh_hh_pair(react_graph: nx.Graph, u: int, v: int) -> bool:
|
|
833
|
+
return (
|
|
834
|
+
HComplete._candidate_node_attr(react_graph, u, "element") == "H"
|
|
835
|
+
and HComplete._candidate_node_attr(react_graph, v, "element") == "H"
|
|
836
|
+
)
|
|
837
|
+
|
|
838
|
+
@staticmethod
|
|
839
|
+
def _candidate_tuple_node_changed(
|
|
840
|
+
react_graph: nx.Graph, prod_graph: nx.Graph, node_id: int
|
|
841
|
+
) -> bool:
|
|
842
|
+
for attr in ("element", "charge", "radical", "valence_electrons"):
|
|
843
|
+
pair = (
|
|
844
|
+
HComplete._candidate_node_attr(react_graph, node_id, attr),
|
|
845
|
+
HComplete._candidate_node_attr(prod_graph, node_id, attr),
|
|
846
|
+
)
|
|
847
|
+
if RCExtractor._pair_diff(pair):
|
|
848
|
+
return True
|
|
849
|
+
|
|
850
|
+
hcount_pair = (
|
|
851
|
+
HComplete._candidate_node_attr(react_graph, node_id, "hcount"),
|
|
852
|
+
HComplete._candidate_node_attr(prod_graph, node_id, "hcount"),
|
|
853
|
+
)
|
|
854
|
+
if RCExtractor._hcount_diff(hcount_pair):
|
|
855
|
+
return True
|
|
856
|
+
|
|
857
|
+
lp_pair = (
|
|
858
|
+
HComplete._candidate_lone_pair_attr(react_graph, node_id),
|
|
859
|
+
HComplete._candidate_lone_pair_attr(prod_graph, node_id),
|
|
860
|
+
)
|
|
861
|
+
return RCExtractor._pair_diff(lp_pair)
|
|
862
|
+
|
|
863
|
+
@staticmethod
|
|
864
|
+
def _add_candidate_comparison_node(
|
|
865
|
+
graph: nx.Graph,
|
|
866
|
+
react_graph: nx.Graph,
|
|
867
|
+
prod_graph: nx.Graph,
|
|
868
|
+
node_id: int,
|
|
869
|
+
format: ITSFormat,
|
|
870
|
+
) -> None:
|
|
871
|
+
if graph.has_node(node_id):
|
|
872
|
+
return
|
|
873
|
+
|
|
874
|
+
if format == "typesGH":
|
|
875
|
+
element = HComplete._candidate_node_attr(react_graph, node_id, "element")
|
|
876
|
+
charge = HComplete._candidate_node_attr(react_graph, node_id, "charge")
|
|
877
|
+
else:
|
|
878
|
+
element = (
|
|
879
|
+
HComplete._candidate_node_attr(react_graph, node_id, "element"),
|
|
880
|
+
HComplete._candidate_node_attr(prod_graph, node_id, "element"),
|
|
881
|
+
)
|
|
882
|
+
charge = (
|
|
883
|
+
HComplete._candidate_node_attr(react_graph, node_id, "charge"),
|
|
884
|
+
HComplete._candidate_node_attr(prod_graph, node_id, "charge"),
|
|
885
|
+
)
|
|
886
|
+
|
|
887
|
+
cmp_element = HComplete._comparison_node_value(element)
|
|
888
|
+
cmp_charge = HComplete._comparison_pair_value(charge)
|
|
889
|
+
graph.add_node(
|
|
890
|
+
node_id,
|
|
891
|
+
cmp_element=cmp_element,
|
|
892
|
+
cmp_charge=cmp_charge,
|
|
893
|
+
cmp_node=f"{cmp_element}|{cmp_charge}",
|
|
894
|
+
)
|
|
895
|
+
|
|
896
|
+
@staticmethod
|
|
897
|
+
def _add_candidate_comparison_edge(
|
|
898
|
+
graph: nx.Graph,
|
|
899
|
+
u: int,
|
|
900
|
+
v: int,
|
|
901
|
+
react_order: Any,
|
|
902
|
+
prod_order: Any,
|
|
903
|
+
) -> None:
|
|
904
|
+
graph.add_edge(
|
|
905
|
+
u,
|
|
906
|
+
v,
|
|
907
|
+
cmp_order=HComplete._comparison_pair_value((react_order, prod_order)),
|
|
908
|
+
)
|
|
909
|
+
|
|
910
|
+
@staticmethod
|
|
911
|
+
def _candidate_node_attr(
|
|
912
|
+
graph: nx.Graph, node_id: int, attr: str, default: Any = None
|
|
913
|
+
) -> Any:
|
|
914
|
+
if default is None:
|
|
915
|
+
default = HComplete._candidate_default(
|
|
916
|
+
ITSConstruction.CORE_NODE_DEFAULTS, attr
|
|
917
|
+
)
|
|
918
|
+
if node_id not in graph:
|
|
919
|
+
return default
|
|
920
|
+
return graph.nodes[node_id].get(attr, default)
|
|
921
|
+
|
|
922
|
+
@staticmethod
|
|
923
|
+
def _candidate_edge_attr(
|
|
924
|
+
graph: nx.Graph,
|
|
925
|
+
u: int,
|
|
926
|
+
v: int,
|
|
927
|
+
attr: str,
|
|
928
|
+
default: Any = None,
|
|
929
|
+
) -> Any:
|
|
930
|
+
if default is None:
|
|
931
|
+
default = HComplete._candidate_default(
|
|
932
|
+
ITSConstruction.CORE_EDGE_DEFAULTS, attr
|
|
933
|
+
)
|
|
934
|
+
if not graph.has_edge(u, v):
|
|
935
|
+
return default
|
|
936
|
+
return graph.edges[u, v].get(attr, default)
|
|
937
|
+
|
|
938
|
+
@staticmethod
|
|
939
|
+
def _candidate_lone_pair_attr(graph: nx.Graph, node_id: int) -> Any:
|
|
940
|
+
if node_id not in graph:
|
|
941
|
+
return HComplete._candidate_default(
|
|
942
|
+
ITSConstruction.CORE_NODE_DEFAULTS, "lone_pairs"
|
|
943
|
+
)
|
|
944
|
+
attrs = graph.nodes[node_id]
|
|
945
|
+
return attrs.get("lone_pairs", attrs.get("lp", 0))
|
|
946
|
+
|
|
947
|
+
@staticmethod
|
|
948
|
+
def _candidate_default(defaults: Dict[str, Any], attr: str) -> Any:
|
|
949
|
+
value = defaults.get(attr)
|
|
950
|
+
return value() if callable(value) else value
|
|
951
|
+
|
|
952
|
+
@staticmethod
|
|
953
|
+
def add_hydrogen_nodes_multiple_utils(
|
|
954
|
+
graph: nx.Graph,
|
|
955
|
+
node_id_pairs: Iterable[Tuple[int, int]],
|
|
956
|
+
atom_map_update: bool = True,
|
|
957
|
+
) -> nx.Graph:
|
|
958
|
+
"""Creates and returns a new graph with added hydrogen nodes based on
|
|
959
|
+
the input graph and node ID pairs.
|
|
960
|
+
|
|
961
|
+
:param graph: The base graph to which the nodes will be added.
|
|
962
|
+
:type graph: nx.Graph
|
|
963
|
+
:param node_id_pairs: Pairs of node IDs (original node, new
|
|
964
|
+
hydrogen node) to link with hydrogen.
|
|
965
|
+
:type node_id_pairs: Iterable[Tuple[int, int]]
|
|
966
|
+
:param atom_map_update: If True, update the 'atom_map' attribute with the new
|
|
967
|
+
hydrogen node ID; otherwise, retain the original node's 'atom_map'.
|
|
968
|
+
:type atom_map_update: bool
|
|
969
|
+
|
|
970
|
+
:return: A new graph instance with the added hydrogen nodes.
|
|
971
|
+
:rtype: nx.Graph
|
|
972
|
+
"""
|
|
973
|
+
new_graph = graph.copy()
|
|
974
|
+
for node_id, new_hydrogen_node_id in node_id_pairs:
|
|
975
|
+
atom_map_val = (
|
|
976
|
+
new_hydrogen_node_id
|
|
977
|
+
if atom_map_update
|
|
978
|
+
else new_graph.nodes[node_id].get("atom_map", 0)
|
|
979
|
+
)
|
|
980
|
+
new_graph.add_node(
|
|
981
|
+
new_hydrogen_node_id,
|
|
982
|
+
charge=0,
|
|
983
|
+
hcount=0,
|
|
984
|
+
aromatic=False,
|
|
985
|
+
element="H",
|
|
986
|
+
atom_map=atom_map_val,
|
|
987
|
+
)
|
|
988
|
+
new_graph.add_edge(
|
|
989
|
+
node_id,
|
|
990
|
+
new_hydrogen_node_id,
|
|
991
|
+
order=1.0,
|
|
992
|
+
bond_type="SINGLE",
|
|
993
|
+
)
|
|
994
|
+
new_graph.nodes[node_id]["hcount"] -= 1
|
|
995
|
+
return new_graph
|