chython 3.0.1__tar.gz → 3.0.2__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.
- {chython-3.0.1/chython.egg-info → chython-3.0.2}/PKG-INFO +1 -1
- {chython-3.0.1 → chython-3.0.2}/chython/core/_ml.pxi +77 -75
- {chython-3.0.1 → chython-3.0.2}/chython/core/reaction.py +25 -9
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/modeling_view_corpus.py +2 -2
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_ml_reaction_transition.py +131 -10
- chython-3.0.2/chython/core/test/test_modeling_view_frozen.py +139 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_reaction_container.py +34 -8
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_enumerate.py +32 -0
- {chython-3.0.1 → chython-3.0.2/chython.egg-info}/PKG-INFO +1 -1
- {chython-3.0.1 → chython-3.0.2}/pyproject.toml +1 -1
- chython-3.0.1/chython/core/test/test_modeling_view_frozen.py +0 -86
- {chython-3.0.1 → chython-3.0.2}/LICENSE +0 -0
- {chython-3.0.1 → chython-3.0.2}/MANIFEST.in +0 -0
- {chython-3.0.1 → chython-3.0.2}/README.md +0 -0
- {chython-3.0.1 → chython-3.0.2}/build_inchi.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/_functions.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_abbreviations.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_canonicalize.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_counts.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_crippen.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_hydrogens.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_implicit.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_isomers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_maccs.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_perceive.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_pharmacophore.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_protomers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_qed.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_residues.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_resonance.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_salts.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_saturate.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_smarts.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_standardize.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_tables.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/_tpsa.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/abbreviations.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/acids.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/covalent_radii.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/crippen.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/hbond.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/maccs.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/maccs_corpus.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/pharmacophore.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/qed_alerts.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/residues.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/resonance.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/rotatable.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/salts.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/standardize_groups.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/standardize_metals.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/sybyl_types.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/tables/tpsa.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/_corpus.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/_oracle.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/gen_standardize_rules.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_abbreviations.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_acids_tsv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_canonicalize.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_counts.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_covalent_radii_tsv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_crippen.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_crippen_tsv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_dependency_direction.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_featurizer_injection.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_featurizer_tables_lazy.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_isomers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_maccs.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_maccs_corpus.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_maccs_tsv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_perceive.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_pharmacophore.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_protomers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_qed.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_qed_alerts_tsv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_reaction_hydrogen_repair.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_reaction_passes.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_residues.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_resonance.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_resonance_tsv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_salts.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_saturate.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_smarts.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_standardize_differential.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_standardize_groups_port.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_standardize_overvalent_nitrogen.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_standardize_rules_examples.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_standardize_rules_merges.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_standardize_rules_tsv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_thiele_is_single_purpose.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_tpsa.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_tpsa_tsv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_valence_report.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/chemistry/test/test_z_translation.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/RULES.md +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_canonical.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_core.pyx +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_descriptors.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_elements.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_facade.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_features.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_fingerprints.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_hydrogens.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_inchi.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_isomorphism.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_kekule.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_log.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_molecule_arena.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_molecule_container.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_molecule_topology.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_molecule_views.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_morgan.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_pach.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_pach3.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_query_arena.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_query_boxes.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_query_container.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_query_seal.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_reaction_passes.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_rings.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_smarts_read.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_smiles_read.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_smiles_write.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_smirks_patch.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_smirks_read.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_sssr.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_stereo.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_thiele.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/_valence.pxi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/elements.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/isotopes.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/arena_v4_corpus.bin.gz +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/bench_ml.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/chytorch_oracle.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/gen_element_tables.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/gen_modeling_view_corpus.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/gen_pach3_corpus.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/gen_reaction_pach_corpus.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/gen_v3_fixtures.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/gen_v4_fixtures.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/gen_valence_rules.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/modeling_view_corpus.json.gz +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/oracle.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/pach3_corpus.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/pach_corpus.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/pach_v0_corpus.bin.gz +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/pach_v0_native_corpus.bin.gz +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/pach_v2_corpus.bin.gz +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/pach_v3_corpus.bin.gz +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/pach_v4_corpus.bin.gz +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/reaction_pach_corpus.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/reaction_pach_v2_corpus.bin.gz +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_aggregates.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_alternative_spellings.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_apply_scratch_probe.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_arena_f60.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_arena_identity.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_arena_v3_compat.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_arena_v4_compat.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_aromatic_storage.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_canonical.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_canonical_mirror.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_cip_storage.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_clean_isotopes_and_coordinate_bonds.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_clean_stereo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_conformers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_container_log.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_copy_caches.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_derive.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_descriptors.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_element_tables.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_facade.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_features.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_featurizer_injection.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_fingerprints.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_geometry.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_h_unknown.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_hydrogens.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_inchi.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_interop_injection.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_isomorphism.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_kekule.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_log.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_magic.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_meta.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_ml_encoding.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_ml_state_view.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_ml_transition_view.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_ml_unpack_differential.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_molecule.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_morgan.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_no_chython_two_imports.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_oracle.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_pach.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_pach3.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_pack.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_query.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_r_edit.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_r_query.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_r_semantics.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_r_serialisation.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_r_smirks.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_r_storage.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_reaction_identity.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_reaction_pach.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_reaction_passes.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_reaction_patch_stereo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_reaction_smiles.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_rings.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_rings_c60.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_set_element.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_sgroups.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smarts_read.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_r.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_read.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_roundtrip.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_write.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_write_aromatic.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_write_cis_trans.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_write_detached.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_write_differential.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_write_h_unknown.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_write_stereo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smiles_write_sticky.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smirks_filter.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smirks_patch.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smirks_read.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smirks_report.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_smirks_stereo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_stereo_acceptance.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_stereo_parity.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_stereo_perception.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_stereo_query.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_stereo_units.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_stereo_v2_differential.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_structure.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_thiele.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_title.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_topology.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_union_stereo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_valence.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/test_view_surface.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/v3_fixtures.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/test/v4_fixtures.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/valence_rules.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/core/wedge.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/_config.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/_hooks.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/bonds.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/colorbar.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/colormap.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/field.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/figure.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/label.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/layout/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/layout/clean2d.js +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/layout/molecule.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/layout/reaction.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/metrics/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/metrics/helvetica.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/metrics/times.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/overlay.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/render/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/render/svg.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/scene.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/style.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_bonds.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_clean2d.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_colorbar.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_colormap.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_field.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_figure.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_label.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_metrics.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_overlay.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_package.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_r_atom.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_scene.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_style.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_svg.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_wedge_draw.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/test/test_x3dom.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/wedge.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/depict/x3dom.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/exceptions.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/_text.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/CTFILE.md +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_ctab.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_errors.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_facade.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_hydrogens.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_rdf.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_rxn.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_sdf.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_sgroup.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_stream.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_tokens.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_v2000.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/_v3000.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/conftest.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_aromatic.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_container_log.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_data_labels.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_facade.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_fidelity.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_hydrogens.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_r_atom.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_rdf.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_rxn.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_sdf.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_sgroup.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_stream.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_tokens.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_v2000.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_v3000.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/ctfile/test/test_wedge.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/mol2.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/pdb/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/pdb/_builder.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/pdb/_legacy.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/pdb/_mmcif.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/pdb/_records.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/pdb/_star.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/conftest.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/oracles.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_conformance.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_done_when.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_isolation.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_log_prefix.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_mmcif.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_mol2.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_no_review_bookkeeping.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_oracles.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_pdb.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_pdb_builder.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_perceive_agreement.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_read_only_facades.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_xyz.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/test/test_xyz_builder.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/_cml.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/_dialect.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/_errors.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/_facade.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/_mrv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/_tree.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/conftest.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/test_cml.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/test_container_log.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/test_dialect.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/test_equivalence.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/test_facade.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/test_mrv.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/test_mrv_census.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xml/test/test_tree.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/formats/xyz.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_cdk.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_cdpkit.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_indigo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_iupac.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_java.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_openbabel.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_pandas.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_rdkit.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_records.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/_stereo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/config.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/conformers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/conftest.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_cdk.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_cdpkit.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_config.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_conformers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_coordinate_honesty.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_dispatch.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_indigo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_iupac.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_log_delivery.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_openbabel.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_pandas.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_rdkit.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_stereo.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/interop/test/test_v2_oracle.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/_enumerate.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/_numbering.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/_reconstruct.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/_stickers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/_tables.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/attention/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/attention/_assign.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/attention/_encode.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/attention/_session.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/tables/functional.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/tables/protective.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/tables/reactions.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/tables/roles.tsv +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/_frozen_ids.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/gen_corpus_glossary.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/golden_subset.smi +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_attention.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_attention_assign.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_attention_encode.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_attention_isolation.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_corpus_glossary.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_dependency_direction.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_functional.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_id_stability.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_numbering.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_probes.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_protective.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_reconstruct.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_roles.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_stickers.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/reactions/test/test_tables.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/__init__.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_code_hygiene.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_container_methods.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_doc_figures.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_doc_references.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_doc_samples.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_facade_names.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_hydrogen_parity.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_libinchi_staging.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_log_records.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_optional_numpy.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_packaging.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_performance.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_r_atom_integration.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_release_build.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_stereo_bluebook.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython/test/test_v2_boundary.py +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython.egg-info/SOURCES.txt +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython.egg-info/dependency_links.txt +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython.egg-info/requires.txt +0 -0
- {chython-3.0.1 → chython-3.0.2}/chython.egg-info/top_level.txt +0 -0
- {chython-3.0.1 → chython-3.0.2}/setup.cfg +0 -0
- {chython-3.0.1 → chython-3.0.2}/setup.py +0 -0
|
@@ -683,23 +683,41 @@ def mol_transition_view(MoleculeContainer molecule not None, TensorEncoding enco
|
|
|
683
683
|
DEF ML_NO_INDEX = 0xffffffff
|
|
684
684
|
|
|
685
685
|
|
|
686
|
-
# `uidx` is `map_number -> union index`, valid only for touched slots
|
|
687
|
-
#
|
|
688
|
-
#
|
|
689
|
-
#
|
|
690
|
-
#
|
|
691
|
-
#
|
|
692
|
-
#
|
|
686
|
+
# `uidx` is `map_number -> union index`, valid only for touched slots, and it is what PAIRS the two
|
|
687
|
+
# sides -- an unmapped atom therefore takes a union row without an entry in it. `rseen` / `pseen` mark
|
|
688
|
+
# which side already claimed a map number. `urow` is indexed by running ordinal over all atoms of both
|
|
689
|
+
# sides (left first, then right) and holds the union row the atom took, or `ML_NO_INDEX` for a rejected
|
|
690
|
+
# collision; the bond passes read it for both endpoints, which is why they need no map number of their
|
|
691
|
+
# own. `head` / `link` are a per-atom singly linked list over bond slots, keyed on the lower union index
|
|
692
|
+
# of the pair. `side` codes: 1 = reactant-only, 2 = product-only, 3 = both. The uidx table is max map
|
|
693
|
+
# number + 1, at most 10000 slots -- initialized slot by slot, not memset, because a three-atom record
|
|
694
|
+
# must not pay for all.
|
|
693
695
|
cdef struct ml_merge_t:
|
|
694
696
|
uint32_t *uidx
|
|
695
697
|
uint8_t *rseen
|
|
696
698
|
uint8_t *pseen
|
|
697
699
|
uint8_t *side # 1 = reactant-only, 2 = product-only, 3 = both
|
|
698
|
-
|
|
700
|
+
uint32_t *urow # union row per atom ordinal; ML_NO_INDEX = a rejected collision
|
|
699
701
|
uint32_t *head
|
|
700
702
|
uint32_t *link
|
|
701
703
|
|
|
702
704
|
|
|
705
|
+
cdef inline void _ml_union_row(ml_union_t *g, ml_merge_t *merge, uint32_t row, atom_t *at,
|
|
706
|
+
uint32_t mn, uint8_t side) noexcept nogil:
|
|
707
|
+
"""One union row from one atom, on the side that atom came from.
|
|
708
|
+
|
|
709
|
+
`h_after` is written equal to `h_before`, which a paired product atom then overwrites. An atom on
|
|
710
|
+
one side only keeps it -- the convention `ReactionModelingView.states` states -- and an unmapped
|
|
711
|
+
atom is one of those, the record having said nothing that would pair it.
|
|
712
|
+
"""
|
|
713
|
+
merge.side[row] = side
|
|
714
|
+
merge.head[row] = ML_NO_INDEX
|
|
715
|
+
g.element[row] = at.element
|
|
716
|
+
g.h_before[row] = at.hydrogens & 0x0f
|
|
717
|
+
g.h_after[row] = at.hydrogens & 0x0f
|
|
718
|
+
g.map_number[row] = <uint16_t> mn
|
|
719
|
+
|
|
720
|
+
|
|
703
721
|
cdef void _ml_union_degrees(ml_union_t *union_graph, ml_merge_t *merge) noexcept nogil:
|
|
704
722
|
"""Per-side heavy degree over the union, by the rule `ReactionModelingView.states` states.
|
|
705
723
|
|
|
@@ -744,9 +762,16 @@ def reaction_transition_view(reactants, products, TensorEncoding encoding=None):
|
|
|
744
762
|
AGENTS ARE EXCLUDED BY NOT BEING PASSED. The caller hands over the two sides it wants unioned, so
|
|
745
763
|
there is no side-kind test inside the kernel to keep in step with the container's notion of one.
|
|
746
764
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
765
|
+
AN UNMAPPED ATOM IS PLACED ON THE SIDE IT CAME FROM, as reactant-only or product-only, and counted
|
|
766
|
+
in `unmapped`. Left out, it takes the degree of every neighbour that stayed down with it: an aryl
|
|
767
|
+
bromide whose bromine carries no number reads two heavy neighbours before the coupling and three
|
|
768
|
+
after, so every aryl halide of one ring gives the same transition state. The price is that an atom
|
|
769
|
+
the record leaves bare on BOTH sides is two rows rather than one, nothing in the record pairing
|
|
770
|
+
them, and `unmapped` is what a consumer that cannot accept that reads.
|
|
771
|
+
|
|
772
|
+
A BADLY MAPPED RECORD IS REPORTED. A map number claimed twice on one side is listed in `collisions`
|
|
773
|
+
and the first claim keeps the row; the second contributes nothing, since a union cannot hold two
|
|
774
|
+
atoms at one key. Refusals live at the answer boundary and this is not one.
|
|
750
775
|
"""
|
|
751
776
|
require_numpy()
|
|
752
777
|
if encoding is None:
|
|
@@ -787,7 +812,7 @@ def reaction_transition_view(reactants, products, TensorEncoding encoding=None):
|
|
|
787
812
|
+ align8(<size_t> slots) # rseen
|
|
788
813
|
+ align8(<size_t> slots) # pseen
|
|
789
814
|
+ align8(<size_t> cap_atoms) # side
|
|
790
|
-
+ align8(<size_t> cap_atoms)
|
|
815
|
+
+ align8(<size_t> cap_atoms * sizeof(uint32_t)) # urow
|
|
791
816
|
+ align8(<size_t> cap_atoms * sizeof(uint32_t)) # head
|
|
792
817
|
+ align8(<size_t> cap_bonds * sizeof(uint32_t)) # link
|
|
793
818
|
+ <size_t> 4 * cap_atoms # element + h_before + n_before + h_after
|
|
@@ -806,7 +831,7 @@ def reaction_transition_view(reactants, products, TensorEncoding encoding=None):
|
|
|
806
831
|
merge.rseen = <uint8_t *> cursor; cursor += align8(<size_t> slots)
|
|
807
832
|
merge.pseen = <uint8_t *> cursor; cursor += align8(<size_t> slots)
|
|
808
833
|
merge.side = <uint8_t *> cursor; cursor += align8(<size_t> cap_atoms)
|
|
809
|
-
merge.
|
|
834
|
+
merge.urow = <uint32_t *> cursor; cursor += align8(<size_t> cap_atoms * sizeof(uint32_t))
|
|
810
835
|
merge.head = <uint32_t *> cursor; cursor += align8(<size_t> cap_atoms * sizeof(uint32_t))
|
|
811
836
|
merge.link = <uint32_t *> cursor; cursor += align8(<size_t> cap_bonds * sizeof(uint32_t))
|
|
812
837
|
union_graph.element = <uint8_t *> cursor; cursor += cap_atoms
|
|
@@ -826,7 +851,7 @@ def reaction_transition_view(reactants, products, TensorEncoding encoding=None):
|
|
|
826
851
|
cdef uint32_t n_union = 0, n_bonds = 0
|
|
827
852
|
cdef uint32_t unmapped_r = 0, unmapped_p = 0
|
|
828
853
|
cdef list collisions_r = [], collisions_p = []
|
|
829
|
-
cdef uint32_t k, mn,
|
|
854
|
+
cdef uint32_t k, mn, n, m, e, base, right_base
|
|
830
855
|
cdef uint32_t edge_to
|
|
831
856
|
cdef uint8_t order
|
|
832
857
|
try:
|
|
@@ -853,26 +878,20 @@ def reaction_transition_view(reactants, products, TensorEncoding encoding=None):
|
|
|
853
878
|
for i in range(n_mol):
|
|
854
879
|
at = atoms + i
|
|
855
880
|
mn = at.map_number
|
|
856
|
-
if
|
|
881
|
+
if mn:
|
|
882
|
+
if merge.rseen[mn]:
|
|
883
|
+
collisions_r.append(mn)
|
|
884
|
+
merge.urow[base + i] = ML_NO_INDEX
|
|
885
|
+
continue
|
|
886
|
+
merge.rseen[mn] = 1
|
|
887
|
+
merge.uidx[mn] = n_union
|
|
888
|
+
else:
|
|
857
889
|
unmapped_r += 1
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
if merge.rseen[mn]:
|
|
861
|
-
collisions_r.append(mn)
|
|
862
|
-
merge.keep[base + i] = 0
|
|
863
|
-
continue
|
|
864
|
-
merge.rseen[mn] = 1
|
|
865
|
-
merge.uidx[mn] = n_union
|
|
866
|
-
merge.side[n_union] = 1
|
|
867
|
-
merge.head[n_union] = ML_NO_INDEX
|
|
868
|
-
merge.keep[base + i] = 1
|
|
869
|
-
union_graph.element[n_union] = at.element
|
|
870
|
-
union_graph.h_before[n_union] = at.hydrogens & 0x0f
|
|
871
|
-
union_graph.h_after[n_union] = at.hydrogens & 0x0f
|
|
872
|
-
union_graph.map_number[n_union] = <uint16_t> mn
|
|
890
|
+
_ml_union_row(&union_graph, &merge, n_union, at, mn, 1)
|
|
891
|
+
merge.urow[base + i] = n_union
|
|
873
892
|
n_union += 1
|
|
874
893
|
base += n_mol
|
|
875
|
-
right_base = base # starting ordinal for product atoms in the
|
|
894
|
+
right_base = base # starting ordinal for product atoms in the urow array
|
|
876
895
|
|
|
877
896
|
# product atoms: a known map number reads its after state onto the existing row, a new one
|
|
878
897
|
# appends -- which is what keeps a component contiguous in the union order
|
|
@@ -883,54 +902,42 @@ def reaction_transition_view(reactants, products, TensorEncoding encoding=None):
|
|
|
883
902
|
for i in range(n_mol):
|
|
884
903
|
at = atoms + i
|
|
885
904
|
mn = at.map_number
|
|
886
|
-
if
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
merge.
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
union_graph.h_after[n] = at.hydrogens & 0x0f
|
|
899
|
-
merge.keep[base + i] = 1
|
|
900
|
-
else:
|
|
905
|
+
if mn:
|
|
906
|
+
if merge.pseen[mn]:
|
|
907
|
+
collisions_p.append(mn)
|
|
908
|
+
merge.urow[base + i] = ML_NO_INDEX
|
|
909
|
+
continue
|
|
910
|
+
merge.pseen[mn] = 1
|
|
911
|
+
if merge.rseen[mn]:
|
|
912
|
+
n = merge.uidx[mn]
|
|
913
|
+
merge.side[n] = 3
|
|
914
|
+
union_graph.h_after[n] = at.hydrogens & 0x0f
|
|
915
|
+
merge.urow[base + i] = n
|
|
916
|
+
continue
|
|
901
917
|
merge.uidx[mn] = n_union
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
union_graph.h_after[n_union] = at.hydrogens & 0x0f
|
|
908
|
-
union_graph.map_number[n_union] = <uint16_t> mn
|
|
909
|
-
n_union += 1
|
|
918
|
+
else:
|
|
919
|
+
unmapped_p += 1
|
|
920
|
+
_ml_union_row(&union_graph, &merge, n_union, at, mn, 2)
|
|
921
|
+
merge.urow[base + i] = n_union
|
|
922
|
+
n_union += 1
|
|
910
923
|
base += n_mol
|
|
911
924
|
|
|
912
|
-
# reactant bonds, both endpoints
|
|
913
|
-
#
|
|
914
|
-
# becoming a self-loop -- that is load-bearing, not incidental.
|
|
925
|
+
# reactant bonds, both endpoints holding a union row: appended in reactant order, `n < m`, so
|
|
926
|
+
# the `n >= m` guard is what visits each bond once.
|
|
915
927
|
base = 0
|
|
916
928
|
for mol in left:
|
|
917
929
|
structure = mol._structure
|
|
918
|
-
atoms = structure.atoms()
|
|
919
930
|
ptr = csr_ptr(structure)
|
|
920
931
|
edges = csr_edges(structure)
|
|
921
932
|
n_mol = structure.header.atom_count
|
|
922
933
|
for i in range(n_mol):
|
|
923
|
-
|
|
934
|
+
n = merge.urow[base + i]
|
|
935
|
+
if n == ML_NO_INDEX:
|
|
924
936
|
continue
|
|
925
|
-
mn = atoms[i].map_number
|
|
926
|
-
n = merge.uidx[mn]
|
|
927
937
|
for k in range(ptr[i], ptr[i + 1]):
|
|
928
938
|
edge_to = edges[k].to
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
mm = atoms[edge_to].map_number
|
|
932
|
-
m = merge.uidx[mm]
|
|
933
|
-
if n >= m:
|
|
939
|
+
m = merge.urow[base + edge_to]
|
|
940
|
+
if m == ML_NO_INDEX or n >= m:
|
|
934
941
|
continue
|
|
935
942
|
union_graph.bond_i[n_bonds] = n
|
|
936
943
|
union_graph.bond_j[n_bonds] = m
|
|
@@ -945,22 +952,17 @@ def reaction_transition_view(reactants, products, TensorEncoding encoding=None):
|
|
|
945
952
|
base = right_base
|
|
946
953
|
for mol in right:
|
|
947
954
|
structure = mol._structure
|
|
948
|
-
atoms = structure.atoms()
|
|
949
955
|
ptr = csr_ptr(structure)
|
|
950
956
|
edges = csr_edges(structure)
|
|
951
957
|
n_mol = structure.header.atom_count
|
|
952
958
|
for i in range(n_mol):
|
|
953
|
-
|
|
959
|
+
n = merge.urow[base + i]
|
|
960
|
+
if n == ML_NO_INDEX:
|
|
954
961
|
continue
|
|
955
|
-
mn = atoms[i].map_number
|
|
956
|
-
n = merge.uidx[mn]
|
|
957
962
|
for k in range(ptr[i], ptr[i + 1]):
|
|
958
963
|
edge_to = edges[k].to
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
mm = atoms[edge_to].map_number
|
|
962
|
-
m = merge.uidx[mm]
|
|
963
|
-
if n >= m:
|
|
964
|
+
m = merge.urow[base + edge_to]
|
|
965
|
+
if m == ML_NO_INDEX or n >= m:
|
|
964
966
|
continue
|
|
965
967
|
order = edges[k].order
|
|
966
968
|
e = merge.head[n]
|
|
@@ -202,8 +202,8 @@ class ReactionModelingView:
|
|
|
202
202
|
number is the only thing that identifies "the same atom" across the arrow -- keying by atom number
|
|
203
203
|
works only where a reader makes the two coincide.
|
|
204
204
|
|
|
205
|
-
IT REPORTS WHAT
|
|
206
|
-
|
|
205
|
+
IT REPORTS WHAT THE RECORD DID NOT STATE instead of leaving it undefined. Calling unmapped atoms
|
|
206
|
+
and colliding map numbers "undefined results" means, for a training set, silent corruption at
|
|
207
207
|
whatever rate the corpus happens to contain. Here they land in :attr:`unmapped` and
|
|
208
208
|
:attr:`collisions`, both empty for a well-mapped reaction, so a pipeline can decide -- and a
|
|
209
209
|
refusal, if one is wanted, happens at the pipeline's boundary rather than inside a container that
|
|
@@ -219,7 +219,11 @@ class ReactionModelingView:
|
|
|
219
219
|
|
|
220
220
|
@property
|
|
221
221
|
def states(self) -> dict[int, tuple]:
|
|
222
|
-
"""`{map_number: (element, h_before, n_before, h_after, n_after)}
|
|
222
|
+
"""`{map_number: (element, h_before, n_before, h_after, n_after)}`, in union order.
|
|
223
|
+
|
|
224
|
+
A NEGATIVE KEY IS AN ATOM THE RECORD DOES NOT NUMBER, allocated `-1` onwards in that order. It
|
|
225
|
+
is placed like any other atom, as reactant-only or product-only; the negative key says the
|
|
226
|
+
pairing is this view's reading of an absence rather than something the record stated.
|
|
223
227
|
|
|
224
228
|
`element` is the atomic number. `h_*` are IMPLICIT hydrogen counts per side and `n_*` are
|
|
225
229
|
heavy-atom neighbour counts per side -- the per-side hydrogen count being the thing the
|
|
@@ -253,9 +257,11 @@ class ReactionModelingView:
|
|
|
253
257
|
def unmapped(self) -> dict[str, int]:
|
|
254
258
|
"""How many atoms carried no map number, per side: `{'reactants': n, 'products': n}`.
|
|
255
259
|
|
|
256
|
-
Not an error and not
|
|
257
|
-
|
|
258
|
-
|
|
260
|
+
Not an error and not a refusal. Each is placed on the side it came from and keyed negatively in
|
|
261
|
+
:attr:`states`, so no neighbour of one loses a degree; what the count is for is the atom the
|
|
262
|
+
record leaves bare on BOTH sides, which becomes two rows because nothing pairs them. A consumer
|
|
263
|
+
that requires a fully mapped reaction checks this rather than discovering the hole in its loss
|
|
264
|
+
curve.
|
|
259
265
|
"""
|
|
260
266
|
return self._unmapped
|
|
261
267
|
|
|
@@ -577,18 +583,28 @@ class ReactionContainer:
|
|
|
577
583
|
that is also a drawing. Stated rather than assumed, because it is the kind of choice a model
|
|
578
584
|
silently trains around.
|
|
579
585
|
|
|
586
|
+
AN UNMAPPED ATOM IS KEYED NEGATIVELY, `-1` onwards in union order, and still counted in
|
|
587
|
+
`unmapped`. It holds a union row like any other atom -- on the side it came from -- so the key
|
|
588
|
+
is only the identity handle a dict needs: 0 would put every such atom on one entry, and a
|
|
589
|
+
positive one would be indistinguishable from a number the record stated.
|
|
590
|
+
|
|
580
591
|
A COLLIDING MAP NUMBER KEEPS ITS FIRST CLAIM. The second atom to claim a number is counted in
|
|
581
592
|
`collisions` and contributes no state and no bond; a union cannot hold two atoms at one key.
|
|
582
593
|
"""
|
|
583
594
|
view = reaction_transition_view(self._reactants, self._products,
|
|
584
595
|
TensorEncoding(unknown_h=H_UNKNOWN))
|
|
585
|
-
|
|
596
|
+
keys, bare = [], 0
|
|
597
|
+
for mn in view.map_numbers.tolist():
|
|
598
|
+
if not mn:
|
|
599
|
+
bare -= 1
|
|
600
|
+
mn = bare
|
|
601
|
+
keys.append(mn)
|
|
586
602
|
states = {mn: (int(view.elements[i]), int(view.h_before[i]), int(view.n_before[i]),
|
|
587
603
|
int(view.h_after[i]), int(view.n_after[i]))
|
|
588
|
-
for i, mn in enumerate(
|
|
604
|
+
for i, mn in enumerate(keys)}
|
|
589
605
|
union = {}
|
|
590
606
|
for (i, j), before, after in zip(view.bonds.tolist(), view.bond_before, view.bond_after):
|
|
591
|
-
a, b =
|
|
607
|
+
a, b = keys[i], keys[j]
|
|
592
608
|
union[(a, b) if a < b else (b, a)] = (int(before), int(after))
|
|
593
609
|
return ReactionModelingView(states, union, view.unmapped, view.collisions)
|
|
594
610
|
|
|
@@ -60,7 +60,7 @@ SMILES = {
|
|
|
60
60
|
# the mirror: 5..8 exist only on the product side
|
|
61
61
|
'tert_butyl_esterification': '[CH3:1][C:2](=[O:3])[OH:9]'
|
|
62
62
|
'>>[CH3:1][C:2](=[O:3])[O:4][C:5]([CH3:6])([CH3:7])[CH3:8].[OH2:9]',
|
|
63
|
-
#
|
|
63
|
+
# two unmapped atoms on each side, counted and placed on the side they came from
|
|
64
64
|
'esterification_partly_mapped': '[CH3:1][C:2](=[O:3])[OH:4].CO'
|
|
65
65
|
'>>[CH3:1][C:2](=[O:3])[O:4]C.O',
|
|
66
66
|
# two atoms sharing map number 1 on the reactant side: the union merges them and says so
|
|
@@ -74,7 +74,7 @@ SMILES = {
|
|
|
74
74
|
# a salt on the product side: two molecules, one of them a single mapped ion
|
|
75
75
|
'saponification': '[CH3:1][C:2](=[O:3])[O:4][CH3:5].[OH-:6].[Na+:7]'
|
|
76
76
|
'>>[CH3:1][C:2](=[O:3])[O-:4].[Na+:7].[CH3:5][OH:6]',
|
|
77
|
-
# no mapping at all: every atom is
|
|
77
|
+
# no mapping at all: every atom is on one side only, so nothing is conserved, and that is a record
|
|
78
78
|
'unmapped_hydrogenation': 'C=C.[H][H]>>CC',
|
|
79
79
|
# an empty product side, which is a record and not an error
|
|
80
80
|
'empty_products': '[CH3:1][CH3:2]>>',
|
|
@@ -40,6 +40,13 @@ def _bonds_by_map(view):
|
|
|
40
40
|
for (i, j), b, a in zip(view.bonds.tolist(), view.bond_before, view.bond_after)}
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
def _columns(view):
|
|
44
|
+
"""Every column but `map_numbers`: what the record states, apart from how it numbers it."""
|
|
45
|
+
return (view.elements.tolist(), view.h_before.tolist(), view.h_after.tolist(),
|
|
46
|
+
view.n_before.tolist(), view.n_after.tolist(), view.bonds.tolist(),
|
|
47
|
+
view.bond_before.tolist(), view.bond_after.tolist())
|
|
48
|
+
|
|
49
|
+
|
|
43
50
|
def test_a_fully_mapped_substitution_reports_both_sides_of_every_atom():
|
|
44
51
|
view = read_reaction_smiles('[CH3:1][Br:2].[OH-:3]>>[CH3:1][OH:3].[Br-:2]').transition_view()
|
|
45
52
|
assert _by_map(view) == {
|
|
@@ -112,10 +119,36 @@ def test_an_agent_contributes_no_atom_and_no_bond():
|
|
|
112
119
|
assert sorted(view.map_numbers.tolist()) == [1, 2, 3, 4, 5, 6]
|
|
113
120
|
|
|
114
121
|
|
|
115
|
-
def
|
|
122
|
+
def test_an_unmapped_atom_is_counted_and_placed_on_the_side_it_came_from():
|
|
123
|
+
"""A record that names one atom still has a whole transition state.
|
|
124
|
+
|
|
125
|
+
`[CH3:1]Br>>[CH3:1]O` states the carbon and nothing else. The bromine is reactant-only and the
|
|
126
|
+
oxygen product-only, so the C-Br bond breaks, the C-O bond forms, and the carbon counts one heavy
|
|
127
|
+
neighbour on each side rather than none. `map_numbers` carries 0 for a row the record does not
|
|
128
|
+
number: the column is the record's own numbering and this view invents no entry in it.
|
|
129
|
+
"""
|
|
130
|
+
view = read_reaction_smiles('[CH3:1]Br>>[CH3:1]O').transition_view()
|
|
131
|
+
assert view.map_numbers.tolist() == [1, 0, 0]
|
|
132
|
+
assert view.elements.tolist() == [6, 35, 8]
|
|
133
|
+
assert view.n_before.tolist() == [1, 1, 0]
|
|
134
|
+
assert view.n_after.tolist() == [1, 0, 1]
|
|
135
|
+
assert view.bonds.tolist() == [[0, 1], [0, 2]]
|
|
136
|
+
assert view.bond_before.tolist() == [1, 0]
|
|
137
|
+
assert view.bond_after.tolist() == [0, 1]
|
|
138
|
+
assert view.unmapped == {'reactants': 1, 'products': 1}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_an_unmapped_atom_on_both_sides_is_two_rows_and_not_one():
|
|
142
|
+
"""The price of placing them, and the reason `unmapped` is still reported.
|
|
143
|
+
|
|
144
|
+
Methanol's carbon and oxygen are unmapped on both sides of this esterification. Nothing in the
|
|
145
|
+
record says the left pair and the right pair are the same two atoms, so the union holds four rows:
|
|
146
|
+
the reactant methanol leaves and the product methyl arrives. A consumer that cannot accept that
|
|
147
|
+
reads `unmapped` and refuses the record.
|
|
148
|
+
"""
|
|
116
149
|
view = read_reaction_smiles('[CH3:1][C:2](=[O:3])[OH:4].CO'
|
|
117
150
|
'>>[CH3:1][C:2](=[O:3])[O:4]C.O').transition_view()
|
|
118
|
-
assert
|
|
151
|
+
assert view.map_numbers.tolist() == [1, 2, 3, 4, 0, 0, 0, 0]
|
|
119
152
|
assert view.unmapped == {'reactants': 2, 'products': 2}
|
|
120
153
|
|
|
121
154
|
|
|
@@ -125,21 +158,109 @@ def test_a_colliding_map_number_is_reported_and_not_refused():
|
|
|
125
158
|
assert view.map_numbers.tolist() == [1, 2, 3]
|
|
126
159
|
|
|
127
160
|
|
|
128
|
-
def
|
|
129
|
-
"""
|
|
161
|
+
def test_a_bond_to_an_unmapped_atom_is_a_union_bond():
|
|
162
|
+
"""Both endpoints have a row, so the bond has one: the union is over atoms, not over numbers."""
|
|
130
163
|
view = read_reaction_smiles('[CH3:1]CO>>[CH3:1]C=O').transition_view()
|
|
131
|
-
assert view.
|
|
132
|
-
assert view.
|
|
164
|
+
assert view.map_numbers.tolist() == [1, 0, 0, 0, 0]
|
|
165
|
+
assert view.bonds.tolist() == [[0, 1], [1, 2], [0, 3], [3, 4]]
|
|
166
|
+
assert view.bond_before.tolist() == [1, 1, 0, 0]
|
|
167
|
+
assert view.bond_after.tolist() == [0, 0, 1, 2]
|
|
168
|
+
|
|
133
169
|
|
|
170
|
+
def test_a_reaction_with_no_mapping_at_all_is_every_atom_on_one_side():
|
|
171
|
+
"""No number anywhere is a record, and the union it gives is the two sides side by side.
|
|
134
172
|
|
|
135
|
-
|
|
173
|
+
Nothing is conserved, because nothing in the record says anything is. `unmapped` counts every
|
|
174
|
+
atom, which is the signal a pipeline refuses on.
|
|
175
|
+
"""
|
|
136
176
|
view = read_reaction_smiles('C=C.[H][H]>>CC').transition_view()
|
|
137
|
-
assert view.
|
|
138
|
-
assert view.
|
|
139
|
-
assert view.
|
|
177
|
+
assert view.map_numbers.tolist() == [0] * 6
|
|
178
|
+
assert view.elements.tolist() == [6, 6, 1, 1, 6, 6]
|
|
179
|
+
assert view.bond_before.tolist() == [2, 1, 0]
|
|
180
|
+
assert view.bond_after.tolist() == [0, 0, 1]
|
|
140
181
|
assert view.unmapped == {'reactants': 4, 'products': 2}
|
|
141
182
|
|
|
142
183
|
|
|
184
|
+
def test_a_changing_atom_moves_its_hydrogens_and_its_bond_order():
|
|
185
|
+
"""`C-OH >> C=O`, the change that needs no atom to leave or arrive.
|
|
186
|
+
|
|
187
|
+
Both atoms of the reaction centre lose a hydrogen and the bond between them goes single to double.
|
|
188
|
+
No degree moves and `unmapped` is zero: a change is a statement about one atom on two sides, so it
|
|
189
|
+
takes a map number to state at all.
|
|
190
|
+
"""
|
|
191
|
+
view = read_reaction_smiles('[CH3:1][CH2:2][OH:3]>>[CH3:1][CH:2]=[O:3]').transition_view()
|
|
192
|
+
assert view.h_before.tolist() == [3, 2, 1]
|
|
193
|
+
assert view.h_after.tolist() == [3, 1, 0]
|
|
194
|
+
assert view.n_before.tolist() == [1, 2, 1]
|
|
195
|
+
assert view.n_after.tolist() == [1, 2, 1], 'nothing left and nothing arrived'
|
|
196
|
+
assert _bonds_by_map(view) == {(1, 2): (1, 1), (2, 3): (1, 2)}
|
|
197
|
+
assert view.unmapped == {'reactants': 0, 'products': 0}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def test_a_leaving_atom_reads_the_same_numbered_or_not():
|
|
201
|
+
"""Being on one side only and being unnumbered are two different facts about an atom.
|
|
202
|
+
|
|
203
|
+
The bromine is reactant-only either way; the number changes its key and nothing else. `unmapped`
|
|
204
|
+
is the only column that separates the two records, which is what makes it the signal to refuse on.
|
|
205
|
+
"""
|
|
206
|
+
numbered = read_reaction_smiles('[CH3:1][Br:2]>>[CH4:1]').transition_view()
|
|
207
|
+
bare = read_reaction_smiles('[CH3:1]Br>>[CH4:1]').transition_view()
|
|
208
|
+
assert _columns(numbered) == _columns(bare)
|
|
209
|
+
assert numbered.map_numbers.tolist() == [1, 2]
|
|
210
|
+
assert bare.map_numbers.tolist() == [1, 0]
|
|
211
|
+
assert numbered.unmapped == {'reactants': 0, 'products': 0}
|
|
212
|
+
assert bare.unmapped == {'reactants': 1, 'products': 0}
|
|
213
|
+
assert bare.n_before.tolist() == [1, 1], 'the carbon has the bromine before'
|
|
214
|
+
assert bare.n_after.tolist() == [0, 0], 'and the bromine left alone, so it counts nobody after'
|
|
215
|
+
assert bare.bond_before.tolist() == [1] and bare.bond_after.tolist() == [0]
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_an_arriving_atom_reads_the_same_numbered_or_not():
|
|
219
|
+
"""The mirror: a product-only atom, numbered or not, is one row whose bonds read `(0, order)`."""
|
|
220
|
+
numbered = read_reaction_smiles('[CH4:1]>>[CH3:1][Br:2]').transition_view()
|
|
221
|
+
bare = read_reaction_smiles('[CH4:1]>>[CH3:1]Br').transition_view()
|
|
222
|
+
assert _columns(numbered) == _columns(bare)
|
|
223
|
+
assert bare.map_numbers.tolist() == [1, 0]
|
|
224
|
+
assert bare.unmapped == {'reactants': 0, 'products': 1}
|
|
225
|
+
assert bare.h_before.tolist() == [4, 0] and bare.h_after.tolist() == [3, 0]
|
|
226
|
+
assert bare.n_before.tolist() == [0, 0] and bare.n_after.tolist() == [1, 1]
|
|
227
|
+
assert bare.bond_before.tolist() == [0] and bare.bond_after.tolist() == [1]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def test_one_record_that_leaves_arrives_and_changes_at_once():
|
|
231
|
+
"""Every branch in one union: two changing atoms, a leaving one, an arriving one, four moved bonds.
|
|
232
|
+
|
|
233
|
+
Maps 2 and 3 are the `C-OH >> C=O` pair. Map 4 (bromine) is reactant-only. Map 6 (water oxygen)
|
|
234
|
+
is product-only. Map 5 is on both sides and loses its only neighbour, so it gains a hydrogen and
|
|
235
|
+
drops to a degree of 0 -- a paired atom reads the departure of an unpaired one.
|
|
236
|
+
"""
|
|
237
|
+
view = read_reaction_smiles('[CH3:1][CH2:2][OH:3].[Br:4][CH3:5]'
|
|
238
|
+
'>>[CH3:1][CH:2]=[O:3].[CH4:5].[OH2:6]').transition_view()
|
|
239
|
+
assert view.map_numbers.tolist() == [1, 2, 3, 4, 5, 6]
|
|
240
|
+
assert view.elements.tolist() == [6, 6, 8, 35, 6, 8]
|
|
241
|
+
assert view.h_before.tolist() == [3, 2, 1, 0, 3, 2]
|
|
242
|
+
assert view.h_after.tolist() == [3, 1, 0, 0, 4, 2]
|
|
243
|
+
assert view.n_before.tolist() == [1, 2, 1, 1, 1, 0]
|
|
244
|
+
assert view.n_after.tolist() == [1, 2, 1, 0, 0, 0]
|
|
245
|
+
assert _bonds_by_map(view) == {(1, 2): (1, 1), (2, 3): (1, 2), (4, 5): (1, 0)}
|
|
246
|
+
assert view.unmapped == {'reactants': 0, 'products': 0}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def test_the_same_record_reads_the_same_where_it_numbers_nothing():
|
|
250
|
+
"""The record above with its bromine and its water unnumbered: one union, two keyings.
|
|
251
|
+
|
|
252
|
+
The leaving atom and the arriving one lose their numbers, and every column but `map_numbers` and
|
|
253
|
+
`unmapped` is unchanged -- including the degree of map 5, which the bromine's row is what preserves.
|
|
254
|
+
"""
|
|
255
|
+
numbered = read_reaction_smiles('[CH3:1][CH2:2][OH:3].[Br:4][CH3:5]'
|
|
256
|
+
'>>[CH3:1][CH:2]=[O:3].[CH4:5].[OH2:6]').transition_view()
|
|
257
|
+
bare = read_reaction_smiles('[CH3:1][CH2:2][OH:3].Br[CH3:5]'
|
|
258
|
+
'>>[CH3:1][CH:2]=[O:3].[CH4:5].O').transition_view()
|
|
259
|
+
assert _columns(numbered) == _columns(bare)
|
|
260
|
+
assert bare.map_numbers.tolist() == [1, 2, 3, 0, 5, 0]
|
|
261
|
+
assert bare.unmapped == {'reactants': 1, 'products': 1}
|
|
262
|
+
|
|
263
|
+
|
|
143
264
|
def test_an_empty_product_side_is_a_record():
|
|
144
265
|
"""Both atoms are reactant-only; they leave together, so each counts the other after."""
|
|
145
266
|
view = read_reaction_smiles('[CH3:1][CH3:2]>>').transition_view()
|