synkit 0.0.6__tar.gz → 0.0.8__tar.gz
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-0.0.6 → synkit-0.0.8}/.github/workflows/build-doc.yml +1 -0
- synkit-0.0.8/.github/workflows/test-and-lint.yml +68 -0
- {synkit-0.0.6 → synkit-0.0.8}/.gitignore +6 -6
- synkit-0.0.8/Data/Figure/synkit.png +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/PKG-INFO +2 -2
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Molecule/test_standardize.py +1 -1
- synkit-0.0.8/Test/Chem/Reaction/test_aam_utils.py +52 -0
- {synkit-0.0.6/Test/Graph/ITS → synkit-0.0.8/Test/Chem/Reaction}/test_aam_validator.py +1 -1
- synkit-0.0.8/Test/Chem/Reaction/test_canon_rsmi.py +52 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/test_deionize.py +1 -1
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Context/test_radius_expand.py +1 -1
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Feature/test_graph_descriptors.py +1 -1
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Hydrogen/test_graph_hydrogen.py +4 -4
- synkit-0.0.8/Test/Graph/Hydrogen/test_misc.py +92 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/ITS/test_its_construction.py +4 -4
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/ITS/test_its_expand.py +2 -1
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/ITS/test_normalize_aam.py +1 -1
- synkit-0.0.8/Test/Graph/MTG/test_group_comp.py +52 -0
- synkit-0.0.8/Test/Graph/MTG/test_groupoid.py +181 -0
- synkit-0.0.8/Test/Graph/MTG/test_mtg.py +39 -0
- {synkit-0.0.6/Test/Graph/Cluster → synkit-0.0.8/Test/Graph/Matcher}/test_batch_cluster.py +1 -1
- {synkit-0.0.6/Test/Graph/Cluster → synkit-0.0.8/Test/Graph/Matcher}/test_graph_cluster.py +6 -3
- synkit-0.0.8/Test/Graph/Matcher/test_graph_matcher.py +158 -0
- {synkit-0.0.6/Test/Graph/Cluster → synkit-0.0.8/Test/Graph/Matcher}/test_graph_morphism.py +1 -1
- synkit-0.0.8/Test/Graph/Matcher/test_subgraph_matcher.py +136 -0
- synkit-0.0.8/Test/Graph/test_canon_graph.py +90 -0
- synkit-0.0.8/Test/Graph/test_syn_graph.py +69 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/IO/test_chemical_converter.py +130 -25
- {synkit-0.0.6 → synkit-0.0.8}/Test/IO/test_dg_to_gml.py +22 -15
- {synkit-0.0.6 → synkit-0.0.8}/Test/IO/test_gml_to_nx.py +1 -1
- {synkit-0.0.6/Test/Rule → synkit-0.0.8/Test/Rule/Apply}/test_reactor_rule.py +7 -2
- {synkit-0.0.6/Test/Rule → synkit-0.0.8/Test/Rule/Apply}/test_retro_reactor.py +5 -1
- {synkit-0.0.6/Test/Rule → synkit-0.0.8/Test/Rule/Apply}/test_rule_rbl.py +5 -1
- {synkit-0.0.6/Test/Rule → synkit-0.0.8/Test/Rule/Compose}/test_rule_compose.py +12 -6
- {synkit-0.0.6/Test/Rule → synkit-0.0.8/Test/Rule/Compose}/test_valance_constrain.py +12 -2
- {synkit-0.0.6/Test/Rule → synkit-0.0.8/Test/Rule/Modify}/test_molecule_rule.py +13 -4
- {synkit-0.0.6/Test/Rule → synkit-0.0.8/Test/Rule/Modify}/test_rule_utils.py +19 -5
- synkit-0.0.8/Test/Rule/test_syn_rule.py +99 -0
- synkit-0.0.8/Test/Synthesis/CRN/test_crn.py +54 -0
- synkit-0.0.8/Test/Synthesis/CRN/test_mod_crn.py +50 -0
- {synkit-0.0.6/Test/Reactor → synkit-0.0.8/Test/Synthesis/MSR}/test_multi_steps.py +6 -3
- {synkit-0.0.6/Test/Reactor → synkit-0.0.8/Test/Synthesis/MSR}/test_path_finder.py +7 -4
- synkit-0.0.8/Test/Synthesis/Reactor/test_core_engine.py +112 -0
- synkit-0.0.6/Test/Reactor/test_reactor_engine.py → synkit-0.0.8/Test/Synthesis/Reactor/test_mod_aam.py +45 -88
- synkit-0.0.8/Test/Synthesis/Reactor/test_mod_reactor.py +153 -0
- synkit-0.0.8/Test/Synthesis/Reactor/test_strategy.py +42 -0
- {synkit-0.0.6/Test/Reactor → synkit-0.0.8/Test/Synthesis}/test_reactor_utils.py +7 -2
- synkit-0.0.8/build-doc.sh +31 -0
- synkit-0.0.8/doc/api.rst +235 -0
- synkit-0.0.8/doc/changelog.rst +76 -0
- synkit-0.0.8/doc/chem.rst +69 -0
- {synkit-0.0.6 → synkit-0.0.8}/doc/conf.py +3 -2
- synkit-0.0.8/doc/figures/aldol.png +0 -0
- synkit-0.0.8/doc/figures/aldol_its.png +0 -0
- synkit-0.0.8/doc/figures/mtg.png +0 -0
- synkit-0.0.8/doc/getting_started.rst +84 -0
- synkit-0.0.8/doc/graph.rst +264 -0
- synkit-0.0.8/doc/index.rst +15 -0
- synkit-0.0.8/doc/io.rst +163 -0
- synkit-0.0.8/doc/reference.rst +6 -0
- synkit-0.0.8/doc/refs.bib +29 -0
- synkit-0.0.8/doc/rule.rst +2 -0
- synkit-0.0.8/doc/synthesis.rst +195 -0
- synkit-0.0.8/environment.yml +9 -0
- synkit-0.0.8/lint.sh +30 -0
- {synkit-0.0.6 → synkit-0.0.8}/pyproject.toml +2 -2
- {synkit-0.0.6 → synkit-0.0.8}/requirements.txt +1 -1
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Molecule/standardize.py +24 -0
- synkit-0.0.8/synkit/Chem/Reaction/__init__.py +4 -0
- synkit-0.0.8/synkit/Chem/Reaction/aam_validator.py +253 -0
- synkit-0.0.8/synkit/Chem/Reaction/canon_rsmi.py +255 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Reaction/rsmi_utils.py +26 -0
- synkit-0.0.8/synkit/Chem/Reaction/standardize.py +151 -0
- synkit-0.0.8/synkit/Chem/__init__.py +1 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Context/hier_context.py +1 -1
- synkit-0.0.8/synkit/Graph/Feature/__init__.py +5 -0
- synkit-0.0.8/synkit/Graph/Feature/wl_hash.py +142 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Hyrogen/_misc.py +232 -90
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Hyrogen/hcomplete.py +1 -1
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Hyrogen/hextend.py +1 -1
- synkit-0.0.8/synkit/Graph/ITS/__init__.py +4 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/ITS/its_construction.py +105 -1
- synkit-0.0.8/synkit/Graph/ITS/its_decompose.py +486 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/ITS/its_expand.py +1 -2
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/ITS/normalize_aam.py +0 -1
- synkit-0.0.8/synkit/Graph/MTG/group_comp.py +158 -0
- synkit-0.0.8/synkit/Graph/MTG/groupoid.py +357 -0
- synkit-0.0.8/synkit/Graph/MTG/mcs_matcher.py +205 -0
- synkit-0.0.8/synkit/Graph/MTG/mtg.py +207 -0
- synkit-0.0.8/synkit/Graph/Matcher/__init__.py +10 -0
- {synkit-0.0.6/synkit/Graph/Cluster → synkit-0.0.8/synkit/Graph/Matcher}/batch_cluster.py +33 -12
- {synkit-0.0.6/synkit/Graph/Cluster → synkit-0.0.8/synkit/Graph/Matcher}/graph_cluster.py +46 -12
- synkit-0.0.8/synkit/Graph/Matcher/graph_matcher.py +320 -0
- synkit-0.0.8/synkit/Graph/Matcher/mcs_matcher.py +202 -0
- synkit-0.0.8/synkit/Graph/Matcher/sing.py +212 -0
- synkit-0.0.8/synkit/Graph/Matcher/subgraph_matcher.py +556 -0
- synkit-0.0.8/synkit/Graph/Matcher/turbo_iso.py +204 -0
- synkit-0.0.8/synkit/Graph/__init__.py +6 -0
- synkit-0.0.8/synkit/Graph/canon_algs.py +257 -0
- synkit-0.0.8/synkit/Graph/canon_graph.py +529 -0
- synkit-0.0.8/synkit/Graph/syn_graph.py +166 -0
- synkit-0.0.8/synkit/Graph/utils.py +159 -0
- synkit-0.0.8/synkit/IO/__init__.py +3 -0
- synkit-0.0.8/synkit/IO/chem_converter.py +456 -0
- synkit-0.0.8/synkit/IO/data_io.py +335 -0
- synkit-0.0.8/synkit/IO/debug.py +75 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/IO/dg_to_gml.py +9 -1
- {synkit-0.0.6 → synkit-0.0.8}/synkit/IO/gml_to_nx.py +34 -2
- {synkit-0.0.6 → synkit-0.0.8}/synkit/IO/graph_to_mol.py +36 -19
- synkit-0.0.8/synkit/IO/mol_to_graph.py +353 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/IO/nx_to_gml.py +80 -74
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Apply}/reactor_rule.py +13 -6
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Apply}/retro_reactor.py +11 -3
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Apply}/rule_rbl.py +11 -5
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Compose}/compose_rule.py +25 -7
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Compose}/rule_compose.py +10 -2
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Compose}/seq_comp.py +3 -3
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Compose}/valence_constrain.py +8 -2
- synkit-0.0.8/synkit/Rule/Modify/implict_rule.py +66 -0
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Modify}/molecule_rule.py +1 -1
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Modify}/prune_templates.py +1 -1
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Modify}/strip_rule.py +1 -1
- synkit-0.0.8/synkit/Rule/__init__.py +1 -0
- synkit-0.0.8/synkit/Rule/syn_rule.py +280 -0
- synkit-0.0.8/synkit/Synthesis/CRN/__init__.py +0 -0
- synkit-0.0.8/synkit/Synthesis/CRN/crn.py +207 -0
- {synkit-0.0.6/synkit/Reactor → synkit-0.0.8/synkit/Synthesis/CRN}/dcrn.py +2 -2
- synkit-0.0.8/synkit/Synthesis/CRN/mod_crn.py +169 -0
- synkit-0.0.8/synkit/Synthesis/MSR/__init__.py +0 -0
- {synkit-0.0.6/synkit/Reactor → synkit-0.0.8/synkit/Synthesis/MSR}/multi_steps.py +13 -9
- synkit-0.0.8/synkit/Synthesis/Metrics/__init__.py +0 -0
- {synkit-0.0.6/synkit → synkit-0.0.8/synkit/Synthesis}/Metrics/_base.py +1 -1
- synkit-0.0.8/synkit/Synthesis/Reactor/__init__.py +0 -0
- synkit-0.0.8/synkit/Synthesis/Reactor/core_engine.py +212 -0
- synkit-0.0.8/synkit/Synthesis/Reactor/mod_aam.py +283 -0
- synkit-0.0.8/synkit/Synthesis/Reactor/mod_reactor.py +446 -0
- synkit-0.0.8/synkit/Synthesis/Reactor/old_syn_reactor.py +443 -0
- {synkit-0.0.6/synkit → synkit-0.0.8/synkit/Synthesis}/Reactor/single_predictor.py +14 -14
- synkit-0.0.8/synkit/Synthesis/Reactor/strategy.py +51 -0
- synkit-0.0.8/synkit/Synthesis/Reactor/syn_reactor.py +561 -0
- synkit-0.0.8/synkit/Synthesis/__init__.py +0 -0
- {synkit-0.0.6/synkit/Reactor → synkit-0.0.8/synkit/Synthesis}/reactor_utils.py +2 -2
- synkit-0.0.8/synkit/Utils/__init__.py +0 -0
- synkit-0.0.8/synkit/Vis/__init__.py +5 -0
- synkit-0.0.8/synkit/Vis/graph_visualizer.py +376 -0
- synkit-0.0.8/synkit/Vis/rule_vis.py +185 -0
- synkit-0.0.8/synkit/Vis/rxn_vis.py +163 -0
- synkit-0.0.8/synkit/__init__.py +0 -0
- synkit-0.0.6/.github/workflows/test-and-lint.yml +0 -55
- synkit-0.0.6/CHANGELOG.md +0 -89
- synkit-0.0.6/Data/Benchmark/conversion_time.json.gz +0 -240767
- synkit-0.0.6/Data/Figure/synkit.png +0 -0
- synkit-0.0.6/Data/Testcase/mech.json.gz +0 -1
- synkit-0.0.6/Data/Testcase/para_rule.json.gz +0 -1
- synkit-0.0.6/Data/Testcase/para_rule_retro.json.gz +0 -1
- synkit-0.0.6/Data/smart.json.gz +0 -1
- synkit-0.0.6/Test/Graph/Cluster/test_rule_morphism.py +0 -103
- synkit-0.0.6/Test/Reactor/test_core_engine.py +0 -112
- synkit-0.0.6/Test/Reactor/test_crn.py +0 -58
- synkit-0.0.6/Test/Vis/test_dpo_vis.py +0 -75
- synkit-0.0.6/doc/getting_started.rst +0 -66
- synkit-0.0.6/doc/index.rst +0 -23
- synkit-0.0.6/doc/references.rst +0 -113
- synkit-0.0.6/lint.sh +0 -7
- synkit-0.0.6/synkit/Chem/Reaction/standardize.py +0 -159
- synkit-0.0.6/synkit/Graph/Cluster/rule_morphism.py +0 -102
- synkit-0.0.6/synkit/Graph/Feature/wl_hash.py +0 -120
- synkit-0.0.6/synkit/Graph/ITS/aam_validator.py +0 -255
- synkit-0.0.6/synkit/Graph/ITS/its_decompose.py +0 -243
- synkit-0.0.6/synkit/IO/chem_converter.py +0 -386
- synkit-0.0.6/synkit/IO/data_io.py +0 -301
- synkit-0.0.6/synkit/IO/debug.py +0 -79
- synkit-0.0.6/synkit/IO/mol_to_graph.py +0 -282
- synkit-0.0.6/synkit/Reactor/core_engine.py +0 -213
- synkit-0.0.6/synkit/Reactor/crn.py +0 -118
- synkit-0.0.6/synkit/Reactor/reactor_engine.py +0 -228
- synkit-0.0.6/synkit/Rule/MaxValence.json.gz +0 -1
- synkit-0.0.6/synkit/Vis/chemical_graph_visualizer.py +0 -378
- synkit-0.0.6/synkit/Vis/chemical_reaction_visualizer.py +0 -133
- synkit-0.0.6/synkit/Vis/dpo_vis.py +0 -103
- synkit-0.0.6/synkit/Vis/graph_visualizer.py +0 -287
- synkit-0.0.6/synkit/Vis/rsmi_to_fig.py +0 -169
- {synkit-0.0.6 → synkit-0.0.8}/.github/workflows/publish-package.yml +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Data/Testcase/Compose/ComposeRule/data.txt +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Data/Testcase/Compose/SingleRule/R0/0.gml +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Data/Testcase/Compose/SingleRule/R0/1.gml +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Data/Testcase/Compose/SingleRule/R0/2.gml +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/LICENSE +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Makefile +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/README.md +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Fingerprint/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Fingerprint/test_fp_calculator.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Fingerprint/test_smiles_featurizer.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Fingerprint/test_transformation_fp.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Molecule/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/test_balance_checker.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/test_cleanning.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/test_fix_aam.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/test_neutralize.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/test_rsmi_utils.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/test_standardize.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/Reaction/test_tautomerize.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Chem/__init__.py +0 -0
- {synkit-0.0.6/Test/Graph/Cluster → synkit-0.0.8/Test/Graph/Context}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Context/test_hier_context.py +0 -0
- {synkit-0.0.6/Test/Graph/Context → synkit-0.0.8/Test/Graph/Feature}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Feature/test_graph_fps.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Feature/test_graph_signature.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Feature/test_hash_fps.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Feature/test_morgan_fps.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Feature/test_path_fps.py +0 -0
- {synkit-0.0.6/Test/Graph/Feature → synkit-0.0.8/Test/Graph/Hydrogen}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Graph/Hydrogen/test_hcomplete.py +0 -0
- {synkit-0.0.6/Test/Graph/Hydrogen → synkit-0.0.8/Test/Graph/ITS}/__init__.py +0 -0
- {synkit-0.0.6/Test/Graph/ITS → synkit-0.0.8/Test/Graph/MTG}/__init__.py +0 -0
- {synkit-0.0.6/Test/Graph → synkit-0.0.8/Test/Graph/Matcher}/__init__.py +0 -0
- {synkit-0.0.6/Test/IO → synkit-0.0.8/Test/Graph}/__init__.py +0 -0
- {synkit-0.0.6/Test/Reactor → synkit-0.0.8/Test/IO}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/IO/test_graph_to_mol.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/IO/test_mol_to_graph.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/IO/test_nx_to_gml.py +0 -0
- {synkit-0.0.6/Test/Rule → synkit-0.0.8/Test/Rule/Apply}/__init__.py +0 -0
- {synkit-0.0.6/Test/Vis → synkit-0.0.8/Test/Rule/Compose}/__init__.py +0 -0
- {synkit-0.0.6/Test → synkit-0.0.8/Test/Rule/Modify}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Chem/Fingerprint → synkit-0.0.8/Test/Rule}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Chem/Molecule → synkit-0.0.8/Test/Synthesis/CRN}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Chem/Reaction → synkit-0.0.8/Test/Synthesis/MSR}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Graph/Cluster → synkit-0.0.8/Test/Synthesis/Reactor}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Graph/Context → synkit-0.0.8/Test/Synthesis}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Graph/Feature → synkit-0.0.8/Test/Vis}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/Test/Vis/test_embedding.py +0 -0
- {synkit-0.0.6/synkit/Graph/Hyrogen → synkit-0.0.8/Test}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/make.bat +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/pytest.sh +0 -0
- {synkit-0.0.6/synkit/IO → synkit-0.0.8/synkit/Chem/Fingerprint}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Fingerprint/fp_calculator.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Fingerprint/smiles_featurizer.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Fingerprint/transformation_fp.py +0 -0
- {synkit-0.0.6/synkit/Metrics → synkit-0.0.8/synkit/Chem/Molecule}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Graph/ITS → synkit-0.0.8/synkit/Chem/Reaction}/aam_utils.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Reaction/balance_check.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Reaction/cleanning.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Reaction/deionize.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Reaction/fix_aam.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Reaction/neutralize.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/Reaction/tautomerize.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Chem/utils.py +0 -0
- {synkit-0.0.6/synkit/Reactor → synkit-0.0.8/synkit/Graph/Context}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Context/radius_expand.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Feature/graph_descriptors.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Feature/graph_fps.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Feature/graph_signature.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Feature/hash_fps.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Feature/morgan_fps.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/Feature/path_fps.py +0 -0
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Graph/Hyrogen}/__init__.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Graph/ITS/its_builder.py +0 -0
- {synkit-0.0.6/synkit/Utils → synkit-0.0.8/synkit/Graph/MTG}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Graph/Cluster → synkit-0.0.8/synkit/Graph/Matcher}/graph_morphism.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/IO/data_process.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/IO/smiles_to_id.py +0 -0
- {synkit-0.0.6/synkit/Vis → synkit-0.0.8/synkit/Rule/Apply}/__init__.py +0 -0
- {synkit-0.0.6/synkit → synkit-0.0.8/synkit/Rule/Compose}/__init__.py +0 -0
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Compose}/rule_mapping.py +0 -0
- /synkit-0.0.6/synkit/Graph/__init.py → /synkit-0.0.8/synkit/Rule/Modify/__init__.py +0 -0
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Modify}/longest_path.py +0 -0
- {synkit-0.0.6/synkit/Rule → synkit-0.0.8/synkit/Rule/Modify}/rule_utils.py +0 -0
- {synkit-0.0.6/synkit/Reactor → synkit-0.0.8/synkit/Synthesis/MSR}/path_finder.py +0 -0
- {synkit-0.0.6/synkit → synkit-0.0.8/synkit/Synthesis}/Metrics/_plot.py +0 -0
- {synkit-0.0.6/synkit → synkit-0.0.8/synkit/Synthesis}/Metrics/_ranking.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Utils/utils.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Vis/chemical_space.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Vis/embedding.py +0 -0
- {synkit-0.0.6 → synkit-0.0.8}/synkit/Vis/pdf_writer.py +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Test & Lint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ "main", "dev", "maintain", "refractor" ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ "main" ]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test-lint:
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
18
|
+
|
|
19
|
+
runs-on: ${{ matrix.os }}
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
# 0) Check out the code
|
|
23
|
+
- uses: actions/checkout@v3
|
|
24
|
+
|
|
25
|
+
# 1) Install Miniconda (downloaded — the “bundled” version was removed)
|
|
26
|
+
- name: Set up Miniconda
|
|
27
|
+
uses: conda-incubator/setup-miniconda@v2
|
|
28
|
+
with:
|
|
29
|
+
miniconda-version: "latest" # <<–‑‑ mandatory or the action fails
|
|
30
|
+
python-version: "3.11"
|
|
31
|
+
auto-update-conda: true
|
|
32
|
+
environment-file: environment.yml
|
|
33
|
+
activate-environment: synkit-env
|
|
34
|
+
use-mamba: true # optional, just faster
|
|
35
|
+
|
|
36
|
+
# 2) Extra Linux‑only dependency: mod ≥ 0.17
|
|
37
|
+
- name: Install mod (Linux only)
|
|
38
|
+
if: matrix.os == 'ubuntu-latest'
|
|
39
|
+
run: conda run -n synkit-env conda install -c jakobandersen -c conda-forge "mod>=0.17" -y
|
|
40
|
+
|
|
41
|
+
# 3) Optional extra project deps via pip (requirements.txt)
|
|
42
|
+
- name: Install project requirements
|
|
43
|
+
if: hashFiles('requirements.txt') != ''
|
|
44
|
+
run: conda run -n synkit-env pip install -r requirements.txt
|
|
45
|
+
|
|
46
|
+
# 4a) Lint on Linux/macOS
|
|
47
|
+
- name: Lint (Unix)
|
|
48
|
+
if: matrix.os != 'windows-latest'
|
|
49
|
+
shell: bash -l {0}
|
|
50
|
+
run: |
|
|
51
|
+
conda activate synkit-env
|
|
52
|
+
bash lint.sh
|
|
53
|
+
|
|
54
|
+
# 4b) Lint on Windows
|
|
55
|
+
- name: Lint (Windows)
|
|
56
|
+
if: matrix.os == 'windows-latest'
|
|
57
|
+
shell: bash -l {0}
|
|
58
|
+
run: |
|
|
59
|
+
conda activate synkit-env
|
|
60
|
+
bash lint.sh
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# 5) Test
|
|
64
|
+
- name: Test
|
|
65
|
+
shell: bash -l {0}
|
|
66
|
+
run: |
|
|
67
|
+
conda activate synkit-env
|
|
68
|
+
bash pytest.sh
|
|
@@ -4,19 +4,19 @@
|
|
|
4
4
|
*/catboost_info/*
|
|
5
5
|
*.ipynb
|
|
6
6
|
*.json
|
|
7
|
-
test_mod.py
|
|
8
|
-
test_format.py
|
|
9
|
-
*dev_zone
|
|
10
7
|
*.pkl.gz
|
|
11
|
-
dev_scripts/*
|
|
12
8
|
*.pdf
|
|
13
9
|
out
|
|
14
10
|
summary
|
|
15
|
-
Data/Benchmark/its.json.gz
|
|
16
|
-
Data/Benchmark/rc.json.gz
|
|
17
11
|
*.log
|
|
18
12
|
.coverage
|
|
19
13
|
dev/*
|
|
20
14
|
*.rdf
|
|
21
15
|
Data/Testcase/hydro/aam.json.gz
|
|
22
16
|
synkit/Chem/FG/*
|
|
17
|
+
test_syn_reactor.py
|
|
18
|
+
Data/Benchmark/*
|
|
19
|
+
# *.png
|
|
20
|
+
*.json.gz
|
|
21
|
+
run.sh
|
|
22
|
+
docs/*
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: synkit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.8
|
|
4
4
|
Summary: Utility for reaction modeling using graph grammar
|
|
5
5
|
Project-URL: homepage, https://github.com/TieuLongPhan/SynKit
|
|
6
6
|
Project-URL: source, https://github.com/TieuLongPhan/SynKit
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
14
14
|
Requires-Python: >=3.11
|
|
15
15
|
Requires-Dist: networkx>=3.3
|
|
16
16
|
Requires-Dist: pandas>=1.5.3
|
|
17
|
-
Requires-Dist: rdkit>=
|
|
17
|
+
Requires-Dist: rdkit>=2025.3.1
|
|
18
18
|
Requires-Dist: regex>=2024.11.6
|
|
19
19
|
Requires-Dist: requests>=2.32.3
|
|
20
20
|
Requires-Dist: scikit-learn>=1.4.0
|
|
@@ -17,7 +17,7 @@ class TestMoleculeFunctions(unittest.TestCase):
|
|
|
17
17
|
|
|
18
18
|
def test_normalize_molecule(self):
|
|
19
19
|
smi = "[Na]OC(=O)c1ccc(C[S+2]([O-])([O-]))cc1"
|
|
20
|
-
expect = "O=C(O[Na])c1ccc(C[S](=O)=O)cc1"
|
|
20
|
+
expect = "O=C([O][Na])c1ccc(C[S](=O)=O)cc1"
|
|
21
21
|
mol = Chem.MolFromSmiles(smi)
|
|
22
22
|
normalized_mol = normalize_molecule(mol)
|
|
23
23
|
self.assertIsInstance(normalized_mol, Chem.Mol)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from rdkit import Chem
|
|
3
|
+
from synkit.Chem.Reaction.aam_utils import enumerate_tautomers, mapping_success_rate
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestChemUtils(unittest.TestCase):
|
|
7
|
+
def test_enumerate_tautomers_simple(self):
|
|
8
|
+
# A simple keto-enol tautomerism: acetylacetone (CC(=O)CC=O) -> same product
|
|
9
|
+
reaction = "CC(=O)CC=O>>O"
|
|
10
|
+
tautomers = enumerate_tautomers(reaction)
|
|
11
|
+
# Should return a list with at least the original reaction
|
|
12
|
+
self.assertIsInstance(tautomers, list)
|
|
13
|
+
self.assertIn(reaction, tautomers)
|
|
14
|
+
# Each entry should be a valid reaction SMILES
|
|
15
|
+
for rsmi in tautomers:
|
|
16
|
+
self.assertIsInstance(rsmi, str)
|
|
17
|
+
parts = rsmi.split(">>")
|
|
18
|
+
self.assertEqual(len(parts), 2)
|
|
19
|
+
# Reactant and product part parseable by RDKit
|
|
20
|
+
self.assertIsNotNone(Chem.MolFromSmiles(parts[0]))
|
|
21
|
+
self.assertIsNotNone(Chem.MolFromSmiles(parts[1]))
|
|
22
|
+
|
|
23
|
+
def test_enumerate_tautomers_invalid(self):
|
|
24
|
+
# Invalid SMILES input
|
|
25
|
+
bad = "INVALID>>SMILES"
|
|
26
|
+
result = enumerate_tautomers(bad)
|
|
27
|
+
# Should return list with original
|
|
28
|
+
self.assertEqual(result, [bad])
|
|
29
|
+
|
|
30
|
+
def test_mapping_success_rate_normal(self):
|
|
31
|
+
data = ["C:1CC", "CCC", "O:3=O", ":5", "N"]
|
|
32
|
+
rate = mapping_success_rate(data)
|
|
33
|
+
# Entries with mapping: 'C:1CC', 'O:3=O', ':5' => 3/5 = 60.0%
|
|
34
|
+
self.assertEqual(rate, 60.0)
|
|
35
|
+
|
|
36
|
+
def test_mapping_success_rate_empty(self):
|
|
37
|
+
with self.assertRaises(ValueError):
|
|
38
|
+
mapping_success_rate([])
|
|
39
|
+
|
|
40
|
+
def test_mapping_success_rate_all(self):
|
|
41
|
+
data = [":1C", ":2", "N:3"]
|
|
42
|
+
rate = mapping_success_rate(data)
|
|
43
|
+
self.assertEqual(rate, 100.0)
|
|
44
|
+
|
|
45
|
+
def test_mapping_success_rate_none(self):
|
|
46
|
+
data = ["C", "O", "N"]
|
|
47
|
+
rate = mapping_success_rate(data)
|
|
48
|
+
self.assertEqual(rate, 0.0)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
unittest.main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import networkx as nx
|
|
3
|
+
from synkit.Chem.Reaction.canon_rsmi import CanonRSMI
|
|
4
|
+
from synkit.IO.chem_converter import rsmi_to_graph
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestCanonRSMI(unittest.TestCase):
|
|
8
|
+
def setUp(self):
|
|
9
|
+
# Use generic backend for deterministic behavior
|
|
10
|
+
self.canon = CanonRSMI(backend="wl", wl_iterations=5)
|
|
11
|
+
# Example reaction SMILES with atom-map labels
|
|
12
|
+
self.input_rsmi = "[CH3:3][CH2:5][OH:10]>>[CH2:3]=[CH2:5].[OH2:10]"
|
|
13
|
+
# After expand_aam and canonicalisation, since backend is generic,
|
|
14
|
+
# we expect the SMILES to remain unchanged (identity)
|
|
15
|
+
self.expected_canonical = "[CH2:1]([CH3:2])[OH:3]>>[CH2:1]=[CH2:2].[OH2:3]"
|
|
16
|
+
|
|
17
|
+
def test_raw_and_canonical_rsmi(self):
|
|
18
|
+
result = self.canon.canonicalise(self.input_rsmi)
|
|
19
|
+
self.assertEqual(result.raw_rsmi, self.input_rsmi)
|
|
20
|
+
self.assertEqual(result.canonical_rsmi, self.expected_canonical)
|
|
21
|
+
|
|
22
|
+
def test_mapping_pairs(self):
|
|
23
|
+
result = self.canon(self.input_rsmi)
|
|
24
|
+
# Mapping pairs should preserve identity mapping
|
|
25
|
+
# mapping_pairs will be matching (map_new, map_old)
|
|
26
|
+
self.assertEqual(sorted(result.mapping_pairs), [(1, 5), (2, 3), (3, 10)])
|
|
27
|
+
|
|
28
|
+
def test_graphs_and_hashes(self):
|
|
29
|
+
result = self.canon(self.input_rsmi)
|
|
30
|
+
# raw graphs should parse correctly
|
|
31
|
+
r_raw, p_raw = rsmi_to_graph(self.input_rsmi)
|
|
32
|
+
self.assertIsInstance(result.raw_reactant_graph, nx.Graph)
|
|
33
|
+
self.assertIsInstance(result.raw_product_graph, nx.Graph)
|
|
34
|
+
# canonical graphs should also be Graph
|
|
35
|
+
self.assertIsInstance(result.canonical_reactant_graph, nx.Graph)
|
|
36
|
+
self.assertIsInstance(result.canonical_product_graph, nx.Graph)
|
|
37
|
+
# reactant_hash and product_hash should match underlying canonicaliser
|
|
38
|
+
h_reac = self.canon._canon.canonical_signature(result.canonical_reactant_graph)
|
|
39
|
+
h_prod = self.canon._canon.canonical_signature(result.canonical_product_graph)
|
|
40
|
+
# canonical_hash is combined
|
|
41
|
+
self.assertEqual(result.canonical_hash, f"{h_reac}>>{h_prod}")
|
|
42
|
+
|
|
43
|
+
def test_idempotence(self):
|
|
44
|
+
# Applying canonicalise twice yields same result
|
|
45
|
+
result1 = self.canon(self.input_rsmi)
|
|
46
|
+
result2 = self.canon(result1.canonical_rsmi)
|
|
47
|
+
self.assertEqual(result1.canonical_rsmi, result2.canonical_rsmi)
|
|
48
|
+
self.assertEqual(result1.mapping_pairs, result2.mapping_pairs)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
unittest.main()
|
|
@@ -34,7 +34,7 @@ class TestDeionize(unittest.TestCase):
|
|
|
34
34
|
def test_uncharge_smiles(self):
|
|
35
35
|
charge_smiles = "[Na+].[OH-]"
|
|
36
36
|
uncharged_smiles = Deionize.uncharge_smiles(charge_smiles)
|
|
37
|
-
self.assertEqual(uncharged_smiles, "
|
|
37
|
+
self.assertEqual(uncharged_smiles, "[OH][Na]")
|
|
38
38
|
|
|
39
39
|
def test_apply_uncharge_smiles_to_reactions(self):
|
|
40
40
|
reactions = [{"reactants": "[NH4+].[OH-]", "products": "N.O"}]
|
|
@@ -3,7 +3,7 @@ import networkx as nx
|
|
|
3
3
|
from synkit.IO.data_io import load_from_pickle
|
|
4
4
|
from synkit.Graph.ITS.its_decompose import get_rc
|
|
5
5
|
from synkit.Graph.Context.radius_expand import RadiusExpand
|
|
6
|
-
from synkit.Graph.
|
|
6
|
+
from synkit.Graph.Matcher.graph_morphism import graph_isomorphism, subgraph_isomorphism
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class TestRadiusExpand(unittest.TestCase):
|
|
@@ -183,7 +183,7 @@ class TestGraphDescriptor(unittest.TestCase):
|
|
|
183
183
|
|
|
184
184
|
# Run the descriptor function
|
|
185
185
|
results = GraphDescriptor.process_entries_in_parallel(
|
|
186
|
-
self.data_parallel, "GraphRules", "ITSGraph", n_jobs=
|
|
186
|
+
self.data_parallel, "GraphRules", "ITSGraph", n_jobs=1
|
|
187
187
|
)
|
|
188
188
|
self.assertEqual(results[0]["topo"], expected_output["topo"])
|
|
189
189
|
self.assertEqual(results[0]["cycle"], expected_output["cycle"])
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import unittest
|
|
2
|
-
from synkit.
|
|
3
|
-
from synkit.Graph.
|
|
2
|
+
from synkit.Chem.Reaction.aam_validator import AAMValidator
|
|
3
|
+
from synkit.Graph.Matcher.graph_morphism import graph_isomorphism
|
|
4
4
|
from synkit.IO.chem_converter import rsmi_to_graph, graph_to_rsmi
|
|
5
|
-
from synkit.Graph.Hyrogen._misc import implicit_hydrogen,
|
|
5
|
+
from synkit.Graph.Hyrogen._misc import implicit_hydrogen, h_to_explicit
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class TestGraphH(unittest.TestCase):
|
|
@@ -53,7 +53,7 @@ class TestGraphH(unittest.TestCase):
|
|
|
53
53
|
|
|
54
54
|
def test_explicit_hydrogen(self):
|
|
55
55
|
r_imp, p_imp = rsmi_to_graph(self.implicit_rsmi)
|
|
56
|
-
r_ex, p_ex =
|
|
56
|
+
r_ex, p_ex = h_to_explicit(r_imp), h_to_explicit(p_imp)
|
|
57
57
|
r, p = rsmi_to_graph(self.rsmi)
|
|
58
58
|
self.assertTrue(graph_isomorphism(r, r_ex))
|
|
59
59
|
self.assertTrue(graph_isomorphism(p, p_ex))
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from synkit.Graph.Hyrogen._misc import (
|
|
4
|
+
has_XH,
|
|
5
|
+
h_to_implicit,
|
|
6
|
+
h_to_explicit,
|
|
7
|
+
check_explicit_hydrogen,
|
|
8
|
+
check_hcount_change,
|
|
9
|
+
)
|
|
10
|
+
from synkit.IO.chem_converter import rsmi_to_its
|
|
11
|
+
from synkit.Graph.ITS.its_decompose import its_decompose
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestHydrogenUtilities(unittest.TestCase):
|
|
15
|
+
|
|
16
|
+
def setUp(self):
|
|
17
|
+
# Explicit hydrogen example
|
|
18
|
+
self.rsmi_explicit = "[C:1]=[C:2].[H:3][H:4]>>[C:1]([H:3])[C:2][H:4]"
|
|
19
|
+
self.its_explicit = rsmi_to_its(self.rsmi_explicit)
|
|
20
|
+
self.rc_explicit = self.its_explicit
|
|
21
|
+
self.r_explicit, self.p_explicit = its_decompose(self.rc_explicit)
|
|
22
|
+
|
|
23
|
+
# Implicit hydrogen example
|
|
24
|
+
self.rsmi_implicit = "[C:1]=[C:2].[H:3][H:4]>>[CH:1][CH:2]"
|
|
25
|
+
self.its_implicit = rsmi_to_its(self.rsmi_implicit)
|
|
26
|
+
self.rc_implicit = self.its_implicit
|
|
27
|
+
self.r_implicit, self.p_implicit = its_decompose(self.rc_implicit)
|
|
28
|
+
|
|
29
|
+
def test_has_XH_explicit(self):
|
|
30
|
+
self.assertTrue(
|
|
31
|
+
has_XH(self.rc_explicit), "Explicit hydrogen bonds should be detected."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def test_has_XH_implicit(self):
|
|
35
|
+
self.assertFalse(
|
|
36
|
+
has_XH(self.rc_implicit),
|
|
37
|
+
"Implicit hydrogen representation should have no explicit X-H bonds.",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def test_h_to_implicit_removes_H_nodes(self):
|
|
41
|
+
G = self.rc_explicit
|
|
42
|
+
heavy_atoms = [n for n, d in G.nodes(data=True) if d.get("element") != "H"]
|
|
43
|
+
G_implicit = h_to_implicit(G)
|
|
44
|
+
h_nodes = [n for n, d in G_implicit.nodes(data=True) if d.get("element") == "H"]
|
|
45
|
+
self.assertEqual(len(h_nodes), 0, "All hydrogen nodes should be removed.")
|
|
46
|
+
for n in heavy_atoms:
|
|
47
|
+
self.assertGreaterEqual(
|
|
48
|
+
G_implicit.nodes[n].get("hcount", 0),
|
|
49
|
+
1,
|
|
50
|
+
"Heavy atoms should have hcount ≥ 1.",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def test_h_to_explicit_adds_H_nodes(self):
|
|
54
|
+
G = self.rc_explicit
|
|
55
|
+
G_implicit = h_to_implicit(G)
|
|
56
|
+
heavy_atoms = [
|
|
57
|
+
n for n, d in G_implicit.nodes(data=True) if d.get("element") != "H"
|
|
58
|
+
]
|
|
59
|
+
G_expanded = h_to_explicit(G_implicit, heavy_atoms)
|
|
60
|
+
h_nodes = [n for n, d in G_expanded.nodes(data=True) if d.get("element") == "H"]
|
|
61
|
+
self.assertGreaterEqual(len(h_nodes), 2, "Hydrogen nodes should be added back.")
|
|
62
|
+
|
|
63
|
+
def test_roundtrip_hydrogen_conversion(self):
|
|
64
|
+
G = self.rc_explicit
|
|
65
|
+
heavy_atoms = [n for n, d in G.nodes(data=True) if d.get("element") != "H"]
|
|
66
|
+
G1 = h_to_implicit(G)
|
|
67
|
+
G2 = h_to_explicit(G1, heavy_atoms)
|
|
68
|
+
h_nodes = [n for n, d in G2.nodes(data=True) if d.get("element") == "H"]
|
|
69
|
+
self.assertGreaterEqual(
|
|
70
|
+
len(h_nodes),
|
|
71
|
+
2,
|
|
72
|
+
"Hydrogens should be recoverable after roundtrip conversion.",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def test_check_explicit_hydrogen(self):
|
|
76
|
+
count, ids = check_explicit_hydrogen(self.rc_explicit)
|
|
77
|
+
self.assertEqual(count, 2, "Should detect 2 explicit hydrogens.")
|
|
78
|
+
self.assertEqual(len(ids), 2)
|
|
79
|
+
for node_id in ids:
|
|
80
|
+
self.assertEqual(self.rc_explicit.nodes[node_id]["element"], "H")
|
|
81
|
+
|
|
82
|
+
def test_check_hcount_change_explicit(self):
|
|
83
|
+
delta = check_hcount_change(self.r_explicit, self.p_explicit)
|
|
84
|
+
self.assertEqual(delta, 2, "Expected hydrogen movement in explicit graph.")
|
|
85
|
+
|
|
86
|
+
def test_check_hcount_change_implicit(self):
|
|
87
|
+
delta = check_hcount_change(self.r_implicit, self.p_implicit)
|
|
88
|
+
self.assertEqual(delta, 2, "Expected hydrogen movement in implicit graph.")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if __name__ == "__main__":
|
|
92
|
+
unittest.main()
|
|
@@ -21,21 +21,21 @@ class TestITSConstruction(unittest.TestCase):
|
|
|
21
21
|
self.H.add_edge(1, 2, order=1) # Different order
|
|
22
22
|
|
|
23
23
|
def test_ITSGraph(self):
|
|
24
|
-
ITS = ITSConstruction.ITSGraph(self.G, self.H)
|
|
24
|
+
ITS = ITSConstruction().ITSGraph(self.G, self.H)
|
|
25
25
|
self.assertTrue(isinstance(ITS, nx.Graph))
|
|
26
26
|
self.assertEqual(len(ITS.nodes()), 2)
|
|
27
27
|
self.assertEqual(len(ITS.edges()), 1)
|
|
28
28
|
self.assertEqual(ITS[1][2]["order"], (2, 1))
|
|
29
29
|
|
|
30
30
|
def test_get_node_attributes_with_defaults(self):
|
|
31
|
-
attributes = ITSConstruction.get_node_attributes_with_defaults(self.G, 1)
|
|
31
|
+
attributes = ITSConstruction().get_node_attributes_with_defaults(self.G, 1)
|
|
32
32
|
self.assertEqual(attributes, ("C", False, 2, 0, ["", ""]))
|
|
33
33
|
|
|
34
34
|
def test_add_edges_to_ITS(self):
|
|
35
35
|
ITS = nx.Graph()
|
|
36
36
|
ITS.add_node(1, element="C", aromatic=False, hcount=3, charge=0)
|
|
37
37
|
ITS.add_node(2, element="C", aromatic=False, hcount=3, charge=0)
|
|
38
|
-
new_ITS = ITSConstruction.add_edges_to_ITS(ITS, self.G, self.H)
|
|
38
|
+
new_ITS = ITSConstruction().add_edges_to_ITS(ITS, self.G, self.H)
|
|
39
39
|
self.assertTrue(isinstance(new_ITS, nx.Graph))
|
|
40
40
|
self.assertEqual(len(new_ITS.edges()), 1)
|
|
41
41
|
self.assertEqual(new_ITS[1][2]["order"], (2, 1))
|
|
@@ -43,7 +43,7 @@ class TestITSConstruction(unittest.TestCase):
|
|
|
43
43
|
def test_add_standard_order_attribute(self):
|
|
44
44
|
graph = nx.Graph()
|
|
45
45
|
graph.add_edge(1, 2, order=(1, 2))
|
|
46
|
-
updated_graph = ITSConstruction.add_standard_order_attribute(graph)
|
|
46
|
+
updated_graph = ITSConstruction().add_standard_order_attribute(graph)
|
|
47
47
|
self.assertEqual(updated_graph[1][2]["standard_order"], -1)
|
|
48
48
|
|
|
49
49
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import unittest
|
|
2
|
-
from synkit.
|
|
2
|
+
from synkit.Chem.Reaction.aam_validator import AAMValidator
|
|
3
3
|
from synkit.Graph.ITS.its_expand import ITSExpand
|
|
4
4
|
|
|
5
5
|
|
|
@@ -12,6 +12,7 @@ class TestPartialExpand(unittest.TestCase):
|
|
|
12
12
|
"[CH3:1][CH2:2][CH2:3][Cl:4].[NH2:5][H:6]"
|
|
13
13
|
+ ">>[CH3:1][CH2:2][CH2:3][NH2:5].[Cl:4][H:6]"
|
|
14
14
|
)
|
|
15
|
+
print(output_rsmi)
|
|
15
16
|
self.assertTrue(AAMValidator.smiles_check(output_rsmi, expected_rsmi, "ITS"))
|
|
16
17
|
|
|
17
18
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
import networkx as nx
|
|
3
3
|
from synkit.Graph.ITS.normalize_aam import NormalizeAAM
|
|
4
|
-
from synkit.
|
|
4
|
+
from synkit.Chem.Reaction.aam_validator import AAMValidator
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class TestNormalizeAAM(unittest.TestCase):
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from synkit.IO.chem_converter import rsmi_to_its
|
|
3
|
+
from synkit.Graph.MTG.groupoid import node_constraint
|
|
4
|
+
from synkit.Graph.MTG.group_comp import GroupComp
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestGroupComp(unittest.TestCase):
|
|
8
|
+
|
|
9
|
+
def setUp(self) -> None:
|
|
10
|
+
test_1 = [
|
|
11
|
+
"[CH:4]([H:7])([H:8])[CH:5]=[O:6]>>[CH:4]([H:8])=[CH:5][O:6]([H:7])",
|
|
12
|
+
"[CH3:1][CH:2]=[O:3].[CH:4]([H:8])=[CH:5][O:6]([H:7])>>[CH3:1][CH:2]([O:3][H:7])[CH:4]([H:8])[CH:5]=[O:6]",
|
|
13
|
+
]
|
|
14
|
+
self.test_graph_1 = [rsmi_to_its(var) for var in test_1]
|
|
15
|
+
test_2 = [
|
|
16
|
+
"[CH2:1]=[CH:2]-[CH2+:3]>>[CH2+:1]-[CH:2]=[CH2:3]",
|
|
17
|
+
"[H:1]-[CH2:2]-[CH2+:3]>>[CH2:2]=[CH2:3].[H+:1]",
|
|
18
|
+
]
|
|
19
|
+
self.test_graph_2 = [rsmi_to_its(var) for var in test_2]
|
|
20
|
+
|
|
21
|
+
def test_get_mapping(self):
|
|
22
|
+
g = GroupComp(self.test_graph_1[0], self.test_graph_1[1])
|
|
23
|
+
m = g.get_mapping(include_singleton=False)
|
|
24
|
+
self.assertEqual(len(m), 4)
|
|
25
|
+
|
|
26
|
+
def test_get_mapping_singleton(self):
|
|
27
|
+
g = GroupComp(self.test_graph_1[0], self.test_graph_1[1])
|
|
28
|
+
m = g.get_mapping(include_singleton=True)
|
|
29
|
+
self.assertEqual(len(m), 10)
|
|
30
|
+
|
|
31
|
+
def test_get_mapping_from_nodes(self):
|
|
32
|
+
m0 = node_constraint(
|
|
33
|
+
self.test_graph_2[0].nodes(data=True), self.test_graph_2[1].nodes(data=True)
|
|
34
|
+
)
|
|
35
|
+
g = GroupComp(self.test_graph_2[0], self.test_graph_2[1])
|
|
36
|
+
m = g.get_mapping_from_nodes(
|
|
37
|
+
m0,
|
|
38
|
+
self.test_graph_2[0].edges(data=True),
|
|
39
|
+
self.test_graph_2[1].edges(data=True),
|
|
40
|
+
)
|
|
41
|
+
self.assertEqual(len(m), 1)
|
|
42
|
+
|
|
43
|
+
def test_get_mapping_fallback(self):
|
|
44
|
+
g = GroupComp(self.test_graph_2[0], self.test_graph_2[1])
|
|
45
|
+
m = g.get_mapping(
|
|
46
|
+
include_singleton=False
|
|
47
|
+
) # even False if cannot find candidate will fall back
|
|
48
|
+
self.assertEqual(len(m), 1)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
unittest.main()
|