synkit 0.0.7__tar.gz → 0.0.9__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.7 → synkit-0.0.9}/.gitignore +2 -1
- synkit-0.0.9/.readthedocs.yml +24 -0
- synkit-0.0.9/Data/Figure/synkit.png +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/PKG-INFO +5 -1
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_canon_rsmi.py +5 -1
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/ITS/test_its_construction.py +4 -4
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/ITS/test_its_expand.py +1 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/IO/test_chemical_converter.py +8 -2
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Modify/test_molecule_rule.py +1 -1
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Modify/test_rule_utils.py +2 -1
- synkit-0.0.9/build-doc.sh +31 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/api.rst +44 -9
- {synkit-0.0.7 → synkit-0.0.9}/doc/conf.py +14 -11
- {synkit-0.0.7 → synkit-0.0.9}/doc/index.rst +1 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/io.rst +12 -12
- synkit-0.0.9/doc/requirements.txt +3 -0
- {synkit-0.0.7 → synkit-0.0.9}/pyproject.toml +6 -2
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/aam_validator.py +3 -3
- synkit-0.0.9/synkit/Graph/Canon/__init__.py +3 -0
- {synkit-0.0.7/synkit/Graph → synkit-0.0.9/synkit/Graph/Canon}/canon_graph.py +11 -2
- synkit-0.0.9/synkit/Graph/Canon/nauty.py +292 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Hyrogen/_misc.py +19 -2
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Hyrogen/hcomplete.py +1 -1
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/ITS/its_construction.py +105 -1
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/ITS/its_expand.py +1 -2
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/ITS/normalize_aam.py +0 -1
- synkit-0.0.9/synkit/Graph/Matcher/__init__.py +10 -0
- synkit-0.0.9/synkit/Graph/Matcher/mcs_matcher.py +202 -0
- synkit-0.0.9/synkit/Graph/Matcher/multi_turbo_iso.py +178 -0
- synkit-0.0.9/synkit/Graph/Matcher/partial_matcher.py +214 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Matcher/turbo_iso.py +8 -5
- synkit-0.0.9/synkit/Graph/__init__.py +16 -0
- synkit-0.0.9/synkit/Graph/canon_graph.py +538 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/chem_converter.py +65 -24
- synkit-0.0.9/synkit/IO/data_io.py +335 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/debug.py +21 -27
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/gml_to_nx.py +34 -2
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/graph_to_mol.py +36 -19
- synkit-0.0.9/synkit/IO/mol_to_graph.py +353 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/nx_to_gml.py +78 -73
- synkit-0.0.9/synkit/Synthesis/Reactor/batch_reactor.py +231 -0
- synkit-0.0.9/synkit/Synthesis/Reactor/rule_filter.py +201 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Reactor/strategy.py +2 -0
- synkit-0.0.7/Data/Figure/synkit.png +0 -0
- synkit-0.0.7/synkit/Graph/Matcher/__init__.py +0 -10
- synkit-0.0.7/synkit/Graph/Matcher/mcs_matcher.py +0 -202
- synkit-0.0.7/synkit/Graph/__init__.py +0 -6
- synkit-0.0.7/synkit/IO/data_io.py +0 -356
- synkit-0.0.7/synkit/IO/mol_to_graph.py +0 -282
- synkit-0.0.7/synkit/Synthesis/Reactor/old_syn_reactor.py +0 -443
- {synkit-0.0.7 → synkit-0.0.9}/.github/workflows/build-doc.yml +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/.github/workflows/publish-package.yml +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/.github/workflows/test-and-lint.yml +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Data/Testcase/Compose/ComposeRule/data.txt +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Data/Testcase/Compose/SingleRule/R0/0.gml +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Data/Testcase/Compose/SingleRule/R0/1.gml +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Data/Testcase/Compose/SingleRule/R0/2.gml +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/LICENSE +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Makefile +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/README.md +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Fingerprint/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Fingerprint/test_fp_calculator.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Fingerprint/test_smiles_featurizer.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Fingerprint/test_transformation_fp.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Molecule/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Molecule/test_standardize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_aam_utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_aam_validator.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_balance_checker.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_cleanning.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_deionize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_fix_aam.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_neutralize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_rsmi_utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_standardize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/Reaction/test_tautomerize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Chem/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Context/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Context/test_hier_context.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Context/test_radius_expand.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Feature/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Feature/test_graph_descriptors.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Feature/test_graph_fps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Feature/test_graph_signature.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Feature/test_hash_fps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Feature/test_morgan_fps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Feature/test_path_fps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Hydrogen/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Hydrogen/test_graph_hydrogen.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Hydrogen/test_hcomplete.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Hydrogen/test_misc.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/ITS/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/ITS/test_normalize_aam.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/MTG/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/MTG/test_group_comp.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/MTG/test_groupoid.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/MTG/test_mtg.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Matcher/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Matcher/test_batch_cluster.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Matcher/test_graph_cluster.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Matcher/test_graph_matcher.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Matcher/test_graph_morphism.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/Matcher/test_subgraph_matcher.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/test_canon_graph.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Graph/test_syn_graph.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/IO/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/IO/test_dg_to_gml.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/IO/test_gml_to_nx.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/IO/test_graph_to_mol.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/IO/test_mol_to_graph.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/IO/test_nx_to_gml.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Apply/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Apply/test_reactor_rule.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Apply/test_retro_reactor.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Apply/test_rule_rbl.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Compose/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Compose/test_rule_compose.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Compose/test_valance_constrain.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/Modify/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Rule/test_syn_rule.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/CRN/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/CRN/test_crn.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/CRN/test_mod_crn.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/MSR/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/MSR/test_multi_steps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/MSR/test_path_finder.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/Reactor/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/Reactor/test_core_engine.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/Reactor/test_mod_aam.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/Reactor/test_mod_reactor.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/Reactor/test_strategy.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Synthesis/test_reactor_utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Vis/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/Vis/test_embedding.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/Test/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/changelog.rst +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/chem.rst +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/figures/aldol.png +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/figures/aldol_its.png +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/figures/mtg.png +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/getting_started.rst +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/graph.rst +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/reference.rst +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/refs.bib +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/rule.rst +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/doc/synthesis.rst +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/environment.yml +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/lint.sh +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/make.bat +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/pytest.sh +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/requirements.txt +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Fingerprint/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Fingerprint/fp_calculator.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Fingerprint/smiles_featurizer.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Fingerprint/transformation_fp.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Molecule/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Molecule/standardize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/aam_utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/balance_check.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/canon_rsmi.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/cleanning.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/deionize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/fix_aam.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/neutralize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/rsmi_utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/standardize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/Reaction/tautomerize.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Chem/utils.py +0 -0
- {synkit-0.0.7/synkit/Graph → synkit-0.0.9/synkit/Graph/Canon}/canon_algs.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Context/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Context/hier_context.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Context/radius_expand.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Feature/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Feature/graph_descriptors.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Feature/graph_fps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Feature/graph_signature.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Feature/hash_fps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Feature/morgan_fps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Feature/path_fps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Feature/wl_hash.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Hyrogen/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Hyrogen/hextend.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/ITS/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/ITS/its_builder.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/ITS/its_decompose.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/MTG/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/MTG/group_comp.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/MTG/groupoid.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/MTG/mcs_matcher.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/MTG/mtg.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Matcher/batch_cluster.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Matcher/graph_cluster.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Matcher/graph_matcher.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Matcher/graph_morphism.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Matcher/sing.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/Matcher/subgraph_matcher.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/syn_graph.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Graph/utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/data_process.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/dg_to_gml.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/IO/smiles_to_id.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Apply/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Apply/reactor_rule.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Apply/retro_reactor.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Apply/rule_rbl.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Compose/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Compose/compose_rule.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Compose/rule_compose.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Compose/rule_mapping.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Compose/seq_comp.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Compose/valence_constrain.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Modify/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Modify/implict_rule.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Modify/longest_path.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Modify/molecule_rule.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Modify/prune_templates.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Modify/rule_utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/Modify/strip_rule.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Rule/syn_rule.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/CRN/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/CRN/crn.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/CRN/dcrn.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/CRN/mod_crn.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/MSR/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/MSR/multi_steps.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/MSR/path_finder.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Metrics/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Metrics/_base.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Metrics/_plot.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Metrics/_ranking.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Reactor/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Reactor/core_engine.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Reactor/mod_aam.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Reactor/mod_reactor.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Reactor/single_predictor.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/Reactor/syn_reactor.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Synthesis/reactor_utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Utils/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Utils/utils.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Vis/__init__.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Vis/chemical_space.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Vis/embedding.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Vis/graph_visualizer.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Vis/pdf_writer.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Vis/rule_vis.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/Vis/rxn_vis.py +0 -0
- {synkit-0.0.7 → synkit-0.0.9}/synkit/__init__.py +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Read the Docs configuration file
|
|
2
|
+
# https://docs.readthedocs.io/en/stable/config-file/v2.html
|
|
3
|
+
|
|
4
|
+
# 1) Tell RTD this is v2 of the schema
|
|
5
|
+
version: 2
|
|
6
|
+
|
|
7
|
+
# 2) Pick your build image and interpreter
|
|
8
|
+
build:
|
|
9
|
+
os: ubuntu-22.04
|
|
10
|
+
tools:
|
|
11
|
+
python: "3.11"
|
|
12
|
+
|
|
13
|
+
# 3) Install your package + any doc-only extras
|
|
14
|
+
python:
|
|
15
|
+
install:
|
|
16
|
+
- method: pip
|
|
17
|
+
path: .
|
|
18
|
+
extra_requirements:
|
|
19
|
+
- docs
|
|
20
|
+
|
|
21
|
+
# 4) Point Sphinx at your conf.py and choose HTML
|
|
22
|
+
sphinx:
|
|
23
|
+
configuration: doc/conf.py
|
|
24
|
+
builder: html
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: synkit
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
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
|
|
@@ -22,6 +22,10 @@ Requires-Dist: seaborn>=0.13.2
|
|
|
22
22
|
Provides-Extra: all
|
|
23
23
|
Requires-Dist: numpy>=2.2.0; extra == 'all'
|
|
24
24
|
Requires-Dist: torch>=2.2.0; extra == 'all'
|
|
25
|
+
Provides-Extra: docs
|
|
26
|
+
Requires-Dist: sphinx-rtd-theme; extra == 'docs'
|
|
27
|
+
Requires-Dist: sphinx>=6.0; extra == 'docs'
|
|
28
|
+
Requires-Dist: sphinxcontrib-bibtex; extra == 'docs'
|
|
25
29
|
Description-Content-Type: text/markdown
|
|
26
30
|
|
|
27
31
|
# SynKit
|
|
@@ -7,7 +7,11 @@ from synkit.IO.chem_converter import rsmi_to_graph
|
|
|
7
7
|
class TestCanonRSMI(unittest.TestCase):
|
|
8
8
|
def setUp(self):
|
|
9
9
|
# Use generic backend for deterministic behavior
|
|
10
|
-
self.canon = CanonRSMI(
|
|
10
|
+
self.canon = CanonRSMI(
|
|
11
|
+
backend="wl",
|
|
12
|
+
wl_iterations=5,
|
|
13
|
+
node_attrs=["element", "aromatic", "charge", "hcount", "neighbors"],
|
|
14
|
+
)
|
|
11
15
|
# Example reaction SMILES with atom-map labels
|
|
12
16
|
self.input_rsmi = "[CH3:3][CH2:5][OH:10]>>[CH2:3]=[CH2:5].[OH2:10]"
|
|
13
17
|
# After expand_aam and canonicalisation, since backend is generic,
|
|
@@ -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
|
|
|
@@ -86,7 +86,10 @@ class TestChemicalConversions(unittest.TestCase):
|
|
|
86
86
|
def test_smiles_to_graph_valid(self):
|
|
87
87
|
# Test converting a valid SMILES to a graph
|
|
88
88
|
result = smiles_to_graph(
|
|
89
|
-
"[CH3:1][CH2:2][OH:3]",
|
|
89
|
+
"[CH3:1][CH2:2][OH:3]",
|
|
90
|
+
False,
|
|
91
|
+
True,
|
|
92
|
+
True,
|
|
90
93
|
)
|
|
91
94
|
self.assertIsInstance(result, nx.Graph)
|
|
92
95
|
self.assertEqual(result.number_of_nodes(), 3)
|
|
@@ -94,7 +97,10 @@ class TestChemicalConversions(unittest.TestCase):
|
|
|
94
97
|
def test_smiles_to_graph_invalid(self):
|
|
95
98
|
# Test converting an invalid SMILES string to a graph
|
|
96
99
|
result = smiles_to_graph(
|
|
97
|
-
"invalid_smiles",
|
|
100
|
+
"invalid_smiles",
|
|
101
|
+
True,
|
|
102
|
+
False,
|
|
103
|
+
False,
|
|
98
104
|
)
|
|
99
105
|
self.assertIsNone(result)
|
|
100
106
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
from synkit.Rule.Modify.molecule_rule import MoleculeRule
|
|
3
|
-
from synkit.Graph.Matcher import GraphMatcherEngine
|
|
3
|
+
from synkit.Graph.Matcher.graph_matcher import GraphMatcherEngine
|
|
4
4
|
import importlib
|
|
5
5
|
|
|
6
6
|
MOD_AVAILABLE = importlib.util.find_spec("mod") is not None
|
|
@@ -7,7 +7,8 @@ from synkit.Rule.Modify.rule_utils import (
|
|
|
7
7
|
strip_context,
|
|
8
8
|
_increment_gml_ids,
|
|
9
9
|
)
|
|
10
|
-
from synkit.Graph.Matcher import GraphMatcherEngine
|
|
10
|
+
from synkit.Graph.Matcher.graph_matcher import GraphMatcherEngine
|
|
11
|
+
from synkit.Graph.Matcher.subgraph_matcher import SubgraphMatch
|
|
11
12
|
import importlib
|
|
12
13
|
|
|
13
14
|
MOD_AVAILABLE = importlib.util.find_spec("mod") is not None
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
echo "Checking and installing documentation dependencies..."
|
|
6
|
+
|
|
7
|
+
# Function to check and install a Python package if missing
|
|
8
|
+
install_if_missing() {
|
|
9
|
+
PACKAGE=$1
|
|
10
|
+
python -c "import $PACKAGE" 2>/dev/null || {
|
|
11
|
+
echo "Installing $PACKAGE..."
|
|
12
|
+
pip install "$PACKAGE"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# Check and install main Sphinx packages
|
|
17
|
+
install_if_missing sphinx
|
|
18
|
+
install_if_missing sphinx_rtd_theme
|
|
19
|
+
|
|
20
|
+
# sphinxcontrib-bibtex can have a dash in its import, so:
|
|
21
|
+
pip show sphinxcontrib-bibtex >/dev/null 2>&1 || {
|
|
22
|
+
echo "Installing sphinxcontrib-bibtex..."
|
|
23
|
+
pip install sphinxcontrib-bibtex
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
echo "Building Sphinx documentation..."
|
|
27
|
+
|
|
28
|
+
# Build the docs (adjust source/build dirs as needed)
|
|
29
|
+
python3 -m sphinx -b html ./doc ./docs
|
|
30
|
+
|
|
31
|
+
echo "Documentation built in ./docs"
|
|
@@ -2,15 +2,6 @@
|
|
|
2
2
|
API
|
|
3
3
|
====
|
|
4
4
|
|
|
5
|
-
IO Module
|
|
6
|
-
=========
|
|
7
|
-
The `IO` module provides tools for handling input and output operations related to the chemical converter. It allows seamless interaction with various chemical data formats.
|
|
8
|
-
|
|
9
|
-
.. automodule:: synkit.IO.chem_converter
|
|
10
|
-
:members:
|
|
11
|
-
:undoc-members:
|
|
12
|
-
:show-inheritance:
|
|
13
|
-
|
|
14
5
|
Chem Module
|
|
15
6
|
===========
|
|
16
7
|
The `Chem` module provides tools for handling input and output operations related to the chemical converter. It allows seamless interaction with various chemical data formats.
|
|
@@ -198,3 +189,47 @@ The ``synkit.Vis`` package offers a suite of **visualization utilities** for bot
|
|
|
198
189
|
:members:
|
|
199
190
|
:undoc-members:
|
|
200
191
|
:show-inheritance:
|
|
192
|
+
|
|
193
|
+
IO Module
|
|
194
|
+
=========
|
|
195
|
+
The `IO` module provides tools for handling input and output operations related to the chemical converter. It allows seamless interaction with various chemical data formats.
|
|
196
|
+
|
|
197
|
+
Chemical Conversion
|
|
198
|
+
-------------------
|
|
199
|
+
.. automodule:: synkit.IO.chem_converter
|
|
200
|
+
:members:
|
|
201
|
+
:undoc-members:
|
|
202
|
+
:show-inheritance:
|
|
203
|
+
|
|
204
|
+
.. automodule:: synkit.IO.mol_to_graph
|
|
205
|
+
:members:
|
|
206
|
+
:undoc-members:
|
|
207
|
+
:show-inheritance:
|
|
208
|
+
|
|
209
|
+
.. automodule:: synkit.IO.graph_to_mol
|
|
210
|
+
:members:
|
|
211
|
+
:undoc-members:
|
|
212
|
+
:show-inheritance:
|
|
213
|
+
|
|
214
|
+
.. automodule:: synkit.IO.nx_to_gml
|
|
215
|
+
:members:
|
|
216
|
+
:undoc-members:
|
|
217
|
+
:show-inheritance:
|
|
218
|
+
|
|
219
|
+
.. automodule:: synkit.IO.gml_to_nx
|
|
220
|
+
:members:
|
|
221
|
+
:undoc-members:
|
|
222
|
+
:show-inheritance:
|
|
223
|
+
|
|
224
|
+
IO Functions
|
|
225
|
+
------------
|
|
226
|
+
|
|
227
|
+
.. automodule:: synkit.IO.data_io
|
|
228
|
+
:members:
|
|
229
|
+
:undoc-members:
|
|
230
|
+
:show-inheritance:
|
|
231
|
+
|
|
232
|
+
.. automodule:: synkit.IO.data_io
|
|
233
|
+
:members:
|
|
234
|
+
:undoc-members:
|
|
235
|
+
:show-inheritance:
|
|
@@ -1,31 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
# For the full list of built-in configuration values, see the documentation:
|
|
4
|
-
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
4
|
+
sys.path.insert(0, os.path.abspath(".."))
|
|
8
5
|
|
|
6
|
+
# -- Project information -----------------------------------------------------
|
|
9
7
|
project = "synkit"
|
|
10
|
-
copyright = "2025, Tieu-Long Phan"
|
|
11
8
|
author = "Tieu-Long Phan"
|
|
9
|
+
release = "0.0.8"
|
|
10
|
+
version = release
|
|
12
11
|
|
|
13
12
|
# -- General configuration ---------------------------------------------------
|
|
14
|
-
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
15
|
-
|
|
16
13
|
extensions = [
|
|
17
14
|
"sphinx.ext.autodoc",
|
|
18
15
|
"sphinx.ext.autosectionlabel",
|
|
19
16
|
"sphinx.ext.githubpages",
|
|
20
17
|
"sphinxcontrib.bibtex",
|
|
18
|
+
# "sphinx.ext.napoleon", # un-comment if using Google/NumPy docstrings
|
|
21
19
|
]
|
|
20
|
+
|
|
22
21
|
bibtex_bibfiles = ["refs.bib"]
|
|
23
22
|
templates_path = ["_templates"]
|
|
24
23
|
exclude_patterns = []
|
|
25
24
|
autosectionlabel_prefix_document = True
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
autodoc_default_options = {
|
|
27
|
+
"members": True,
|
|
28
|
+
"undoc-members": True,
|
|
29
|
+
"show-inheritance": True,
|
|
30
|
+
}
|
|
29
31
|
|
|
32
|
+
# -- Options for HTML output -------------------------------------------------
|
|
30
33
|
html_theme = "sphinx_rtd_theme"
|
|
31
34
|
html_static_path = ["_static"]
|
|
@@ -102,31 +102,31 @@ Set ``core=True`` to include only the **reaction center**, and ``useSmile=True``
|
|
|
102
102
|
:linenos:
|
|
103
103
|
|
|
104
104
|
from synkit.IO import (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
rsmi_to_its,
|
|
106
|
+
smart_to_gml,
|
|
107
|
+
its_to_gml,
|
|
108
|
+
save_text_as_gml,
|
|
109
|
+
load_gml_as_text,
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
# Define the aldol reaction template
|
|
113
113
|
reaction = (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
'[CH3:1][CH:2]=[O:3].'
|
|
115
|
+
'[CH:4]([H:7])([H:8])[CH:5]=[O:6]'
|
|
116
|
+
'>>'
|
|
117
|
+
'[CH3:1][CH:2]=[CH:4][CH:5]=[O:6].'
|
|
118
|
+
'[O:3]([H:7])([H:8])'
|
|
119
119
|
)
|
|
120
120
|
|
|
121
121
|
# Option 1: Direct SMARTS → GML
|
|
122
|
-
gml_rule_1 = smart_to_gml(reaction, core=True,
|
|
122
|
+
gml_rule_1 = smart_to_gml(reaction, core=True, useSmiles=False)
|
|
123
123
|
|
|
124
124
|
# Option 2: SMILES → ITS → GML
|
|
125
125
|
its_graph = rsmi_to_its(reaction, core=True)
|
|
126
126
|
gml_rule_2 = its_to_gml(its_graph, core=True)
|
|
127
127
|
|
|
128
128
|
# Save to disk
|
|
129
|
-
save_text_as_gml("aldol_rule.gml"
|
|
129
|
+
save_text_as_gml(gml_text=gml_rule_2, file_path="aldol_rule.gml")
|
|
130
130
|
|
|
131
131
|
# Load back into text
|
|
132
132
|
loaded_rule = load_gml_as_text("aldol_rule.gml")
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "synkit"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.9"
|
|
8
8
|
authors = [
|
|
9
9
|
{name="Tieu Long Phan", email="tieu@bioinf.uni-leipzig.de"}
|
|
10
10
|
]
|
|
@@ -30,7 +30,11 @@ dependencies = [
|
|
|
30
30
|
|
|
31
31
|
[project.optional-dependencies]
|
|
32
32
|
all = ["numpy>=2.2.0", "torch>=2.2.0"]
|
|
33
|
-
|
|
33
|
+
docs = [
|
|
34
|
+
"sphinx>=6.0",
|
|
35
|
+
"sphinx-rtd-theme",
|
|
36
|
+
"sphinxcontrib-bibtex",
|
|
37
|
+
]
|
|
34
38
|
[project.urls]
|
|
35
39
|
homepage = "https://github.com/TieuLongPhan/SynKit"
|
|
36
40
|
source = "https://github.com/TieuLongPhan/SynKit"
|
|
@@ -85,10 +85,10 @@ class AAMValidator:
|
|
|
85
85
|
its_graphs, rc_graphs = [], []
|
|
86
86
|
try:
|
|
87
87
|
for rsmi in (mapped_smile, ground_truth):
|
|
88
|
-
G, H = rsmi_to_graph(
|
|
89
|
-
|
|
88
|
+
G, H = rsmi_to_graph(rsmi=rsmi, sanitize=True, drop_non_aam=True)
|
|
89
|
+
its = ITSConstruction().ITSGraph(
|
|
90
|
+
G, H, ignore_aromaticity=ignore_aromaticity
|
|
90
91
|
)
|
|
91
|
-
its = ITSConstruction.ITSGraph(G, H, ignore_aromaticity)
|
|
92
92
|
its_graphs.append(its)
|
|
93
93
|
rc_graphs.append(get_rc(its))
|
|
94
94
|
|
|
@@ -63,6 +63,7 @@ from networkx.algorithms.graph_hashing import (
|
|
|
63
63
|
weisfeiler_lehman_subgraph_hashes as _wl_hashes,
|
|
64
64
|
)
|
|
65
65
|
from .canon_algs import canon_morgan
|
|
66
|
+
from .nauty import NautyCanonicalizer
|
|
66
67
|
|
|
67
68
|
__all__: list[str] = ["CanonicalGraph", "GraphCanonicaliser", "CanonicalRule"]
|
|
68
69
|
|
|
@@ -145,14 +146,14 @@ class GraphCanonicaliser:
|
|
|
145
146
|
def __init__(
|
|
146
147
|
self,
|
|
147
148
|
*,
|
|
148
|
-
backend: Literal["generic", "wl", "morgan"] = "generic",
|
|
149
|
+
backend: Literal["generic", "wl", "morgan", "nauty"] = "generic",
|
|
149
150
|
wl_iterations: int = 3,
|
|
150
151
|
morgan_radius: int = 3,
|
|
151
152
|
node_attrs: List[str] = ["element", "aromatic", "charge", "hcount"],
|
|
152
153
|
node_sort_key: T_NodeSortKey = _default_node_key,
|
|
153
154
|
edge_sort_key: T_EdgeSortKey = _default_edge_key,
|
|
154
155
|
) -> None:
|
|
155
|
-
if backend not in {"generic", "wl", "morgan"}:
|
|
156
|
+
if backend not in {"generic", "wl", "morgan", "nauty"}:
|
|
156
157
|
raise ValueError("backend must be 'generic' or 'wl' or 'morgan' ")
|
|
157
158
|
self.backend: Literal["generic", "wl", "morgan"] = backend
|
|
158
159
|
self._wl_k: int = wl_iterations
|
|
@@ -161,6 +162,8 @@ class GraphCanonicaliser:
|
|
|
161
162
|
self._edge_key: T_EdgeSortKey = edge_sort_key
|
|
162
163
|
self._wl_node_attrs: Tuple[str, ...] = tuple(node_attrs)
|
|
163
164
|
self._mg_node_attrs: List[str] = node_attrs
|
|
165
|
+
if self.backend == "nauty":
|
|
166
|
+
self.nauty = NautyCanonicalizer(node_attrs=node_attrs, edge_attrs=["order"])
|
|
164
167
|
|
|
165
168
|
# ------------------------------------------------------------------ #
|
|
166
169
|
# High‑level helpers #
|
|
@@ -220,6 +223,8 @@ class GraphCanonicaliser:
|
|
|
220
223
|
return self._canon_generic(g)
|
|
221
224
|
elif self.backend == "wl":
|
|
222
225
|
return self._canon_wl(g)
|
|
226
|
+
elif self.backend == "nauty":
|
|
227
|
+
return self._canon_nauty(g)
|
|
223
228
|
else:
|
|
224
229
|
return canon_morgan(
|
|
225
230
|
g, morgan_radius=self._mg_k, node_attributes=self._mg_node_attrs
|
|
@@ -228,6 +233,9 @@ class GraphCanonicaliser:
|
|
|
228
233
|
# self._canon_generic(g) if self.backend == "generic" else self._canon_wl(g)
|
|
229
234
|
# )
|
|
230
235
|
|
|
236
|
+
def _canon_nauty(self, g: nx.Graph) -> nx.Graph:
|
|
237
|
+
return self.nauty.canonical_form(g)
|
|
238
|
+
|
|
231
239
|
def _canon_generic(self, g: nx.Graph) -> nx.Graph:
|
|
232
240
|
"""Pure attribute‑sort strategy – O(|V| log |V| + |E| log |E|)."""
|
|
233
241
|
nodes_sorted = sorted(g.nodes(data=True), key=lambda x: self._node_key(*x))
|
|
@@ -274,6 +282,7 @@ class GraphCanonicaliser:
|
|
|
274
282
|
wl_hash = _wl_hashes(
|
|
275
283
|
g2,
|
|
276
284
|
node_attr=node_attr,
|
|
285
|
+
edge_attr="order",
|
|
277
286
|
iterations=self._wl_k,
|
|
278
287
|
)
|
|
279
288
|
|