synkit 1.6.5__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- synkit/CRN/Benchmark/__init__.py +53 -0
- synkit/CRN/Benchmark/crosschecks.py +13 -0
- synkit/CRN/Benchmark/kegg.py +12 -0
- synkit/CRN/Benchmark/networks.py +13 -0
- synkit/CRN/Benchmark/scaling.py +13 -0
- synkit/CRN/Benchmark/validate.py +13 -0
- synkit/CRN/Construct/__init__.py +16 -0
- synkit/CRN/Construct/abstract.py +668 -0
- synkit/CRN/Construct/arity.py +36 -0
- synkit/CRN/Construct/builder.py +619 -0
- synkit/CRN/Construct/derivation.py +63 -0
- synkit/CRN/Construct/flattener.py +100 -0
- synkit/CRN/Construct/keys.py +14 -0
- synkit/CRN/Construct/mixtures.py +117 -0
- synkit/CRN/Construct/rdkit_worker.py +69 -0
- synkit/CRN/Construct/smiles.py +99 -0
- synkit/CRN/Construct/state.py +31 -0
- synkit/CRN/Construct/strategy.py +75 -0
- synkit/CRN/Construct/worker.py +42 -0
- synkit/CRN/IO/__init__.py +36 -0
- synkit/CRN/IO/sbml.py +925 -0
- synkit/CRN/Pathway/__init__.py +72 -0
- synkit/CRN/Pathway/_adapter.py +333 -0
- synkit/CRN/Pathway/pathfinder.py +500 -0
- synkit/CRN/Pathway/reachability.py +796 -0
- synkit/CRN/Pathway/realizability.py +1322 -0
- synkit/CRN/Petrinet/__init__.py +93 -0
- synkit/CRN/Petrinet/analyzer.py +486 -0
- synkit/CRN/Petrinet/minimal_semiflows.py +436 -0
- synkit/CRN/Petrinet/net.py +1041 -0
- synkit/CRN/Petrinet/persistence.py +97 -0
- synkit/CRN/Petrinet/semiflows.py +483 -0
- synkit/CRN/Petrinet/siphon_search.py +402 -0
- synkit/CRN/Petrinet/structure.py +286 -0
- synkit/CRN/Props/__init__.py +130 -0
- synkit/CRN/Props/_rank.py +29 -0
- synkit/CRN/Props/deficiency.py +953 -0
- synkit/CRN/Props/dynamics.py +832 -0
- synkit/CRN/Props/helper.py +151 -0
- synkit/CRN/Props/stoich.py +751 -0
- synkit/CRN/Props/thermo.py +584 -0
- synkit/CRN/Query/__init__.py +66 -0
- synkit/CRN/Query/cache.py +41 -0
- synkit/CRN/Query/kegg_api.py +99 -0
- synkit/CRN/Query/kegg_extract.py +714 -0
- synkit/CRN/Query/kegg_impute.py +707 -0
- synkit/CRN/Query/kegg_parse.py +480 -0
- synkit/CRN/Query/to_syncrn.py +290 -0
- synkit/CRN/README.md +234 -0
- synkit/CRN/Structure/__init__.py +12 -0
- synkit/CRN/Structure/_graph_io.py +713 -0
- synkit/CRN/Structure/_matrices.py +88 -0
- synkit/CRN/Structure/_parse.py +544 -0
- synkit/CRN/Structure/reaction.py +237 -0
- synkit/CRN/Structure/rule.py +55 -0
- synkit/CRN/Structure/species.py +46 -0
- synkit/CRN/Structure/syncrn.py +929 -0
- synkit/CRN/Symmetry/__init__.py +20 -0
- synkit/CRN/Symmetry/_common.py +1059 -0
- synkit/CRN/Symmetry/_ir.py +940 -0
- synkit/CRN/Symmetry/automorphism.py +472 -0
- synkit/CRN/Symmetry/canon.py +441 -0
- synkit/CRN/Symmetry/isomorphism.py +412 -0
- synkit/CRN/Symmetry/symmetry.py +61 -0
- synkit/CRN/Symmetry/wl_canon.py +967 -0
- synkit/CRN/Visualize/__init__.py +11 -0
- synkit/CRN/Visualize/labels.py +113 -0
- synkit/CRN/Visualize/layout.py +708 -0
- synkit/CRN/Visualize/palette.py +292 -0
- synkit/CRN/Visualize/validation.py +122 -0
- synkit/CRN/Visualize/vis.py +1152 -0
- synkit/CRN/__init__.py +233 -0
- synkit/CRN/_build.py +50 -0
- synkit/CRN/_native_build.py +175 -0
- synkit/CRN/analysis.py +629 -0
- synkit/CRN/backend.py +74 -0
- synkit/CRN/cpp/CMakeLists.txt +58 -0
- synkit/CRN/cpp/algebra.cpp +46 -0
- synkit/CRN/cpp/closure.cpp +29 -0
- synkit/CRN/cpp/exact.h +55 -0
- synkit/CRN/cpp/pathway.cpp +46 -0
- synkit/CRN/cpp/semiflows.cpp +209 -0
- synkit/CRN/cpp/structural.cpp +240 -0
- synkit/CRN/cpp/symmetry.cpp +45 -0
- synkit/CRN/cpp/write_manifest.cmake +28 -0
- synkit/CRN/kinds.py +137 -0
- synkit/CRN/lib/synkit_crn.dll +0 -0
- synkit/CRN/lib/synkit_crn.json +33 -0
- synkit/CRN/native.py +388 -0
- synkit/CRN/native_analysis.py +459 -0
- synkit/Chem/Cluster/__init__.py +0 -0
- synkit/Chem/Cluster/butina.py +140 -0
- synkit/Chem/Fingerprint/__init__.py +0 -0
- synkit/Chem/Fingerprint/fp_calculator.py +155 -0
- synkit/Chem/Fingerprint/smiles_featurizer.py +258 -0
- synkit/Chem/Fingerprint/transformation_fp.py +139 -0
- synkit/Chem/Mapper/README.rst +43 -0
- synkit/Chem/Mapper/__init__.py +255 -0
- synkit/Chem/Mapper/_compat.py +130 -0
- synkit/Chem/Mapper/adapters/__init__.py +1 -0
- synkit/Chem/Mapper/adapters/prediction.py +126 -0
- synkit/Chem/Mapper/adapters/template.py +412 -0
- synkit/Chem/Mapper/chem/__init__.py +52 -0
- synkit/Chem/Mapper/chem/aam.py +673 -0
- synkit/Chem/Mapper/chem/blind.py +160 -0
- synkit/Chem/Mapper/chem/its.py +309 -0
- synkit/Chem/Mapper/chem/smiles.py +564 -0
- synkit/Chem/Mapper/graph/__init__.py +66 -0
- synkit/Chem/Mapper/graph/automorphism.py +395 -0
- synkit/Chem/Mapper/graph/blockcut.py +98 -0
- synkit/Chem/Mapper/graph/labeled_graph.py +104 -0
- synkit/Chem/Mapper/graph/refine.py +176 -0
- synkit/Chem/Mapper/graph/synkit_adapter.py +110 -0
- synkit/Chem/Mapper/io/__init__.py +13 -0
- synkit/Chem/Mapper/io/idxmapstr.py +82 -0
- synkit/Chem/Mapper/mapper.py +685 -0
- synkit/Chem/Mapper/reaction_search.py +554 -0
- synkit/Chem/Mapper/reporting/__init__.py +1 -0
- synkit/Chem/Mapper/reporting/alternatives.py +451 -0
- synkit/Chem/Mapper/reporting/analysis.py +681 -0
- synkit/Chem/Mapper/reporting/native_analysis.py +485 -0
- synkit/Chem/Mapper/reporting/spectrum.py +642 -0
- synkit/Chem/Mapper/solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/__init__.py +141 -0
- synkit/Chem/Mapper/solvers/exact/assignment/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_certificate.py +113 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_domains.py +162 -0
- synkit/Chem/Mapper/solvers/exact/assignment/assignment_verification.py +58 -0
- synkit/Chem/Mapper/solvers/exact/assignment/incremental_assignment.py +247 -0
- synkit/Chem/Mapper/solvers/exact/certificate.py +128 -0
- synkit/Chem/Mapper/solvers/exact/core.py +183 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/bounds.py +319 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/exhaustive.py +179 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/inputs.py +283 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/records.py +242 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/search.py +1025 -0
- synkit/Chem/Mapper/solvers/exact/distance_search/verify.py +378 -0
- synkit/Chem/Mapper/solvers/exact/edit_support.py +375 -0
- synkit/Chem/Mapper/solvers/exact/hybrid.py +224 -0
- synkit/Chem/Mapper/solvers/exact/hydrogen.py +264 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/branching.py +499 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumerate.py +1050 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/enumeration_result.py +30 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/kernel.py +256 -0
- synkit/Chem/Mapper/solvers/exact/kernel_solvers/milp.py +194 -0
- synkit/Chem/Mapper/solvers/exact/native/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/native/build.py +154 -0
- synkit/Chem/Mapper/solvers/exact/native/candidates.py +593 -0
- synkit/Chem/Mapper/solvers/exact/native/canonical.py +396 -0
- synkit/Chem/Mapper/solvers/exact/native/disk_frontier.py +415 -0
- synkit/Chem/Mapper/solvers/exact/native/frontier.py +390 -0
- synkit/Chem/Mapper/solvers/exact/native/hydrogen_quotient.py +213 -0
- synkit/Chem/Mapper/solvers/exact/native/its.py +528 -0
- synkit/Chem/Mapper/solvers/exact/native/native_distance.cpp +2803 -0
- synkit/Chem/Mapper/solvers/exact/native/orbit_aggregation.py +328 -0
- synkit/Chem/Mapper/solvers/exact/native/parallel.py +205 -0
- synkit/Chem/Mapper/solvers/exact/native/pmcd.py +203 -0
- synkit/Chem/Mapper/solvers/exact/native/runtime.py +40 -0
- synkit/Chem/Mapper/solvers/exact/native/search.py +294 -0
- synkit/Chem/Mapper/solvers/exact/native/separator.py +224 -0
- synkit/Chem/Mapper/solvers/exact/native_build.py +12 -0
- synkit/Chem/Mapper/solvers/exact/pabs/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/pabs/cost_lattice.py +43 -0
- synkit/Chem/Mapper/solvers/exact/pabs/factor_spectrum.py +110 -0
- synkit/Chem/Mapper/solvers/exact/pabs/multi_shell.py +368 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation.py +679 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_bounds.py +436 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_limits.py +13 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_search.py +856 -0
- synkit/Chem/Mapper/solvers/exact/pabs/propagation_symmetry.py +66 -0
- synkit/Chem/Mapper/solvers/exact/pabs/residual_typed_bonds.py +136 -0
- synkit/Chem/Mapper/solvers/exact/pabs/reward_frontier.py +201 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_bound.py +258 -0
- synkit/Chem/Mapper/solvers/exact/pabs/separator_spectrum.py +308 -0
- synkit/Chem/Mapper/solvers/exact/pabs/sparse_reward_bound.py +207 -0
- synkit/Chem/Mapper/solvers/exact/pabs/suffix_spectrum.py +299 -0
- synkit/Chem/Mapper/solvers/exact/search.py +55 -0
- synkit/Chem/Mapper/solvers/exact/seeds/__init__.py +1 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed.py +104 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_fragments.py +148 -0
- synkit/Chem/Mapper/solvers/exact/seeds/seed_relaxation.py +181 -0
- synkit/Chem/Mapper/solvers/exact/symmetry.py +223 -0
- synkit/Chem/Mapper/solvers/native/__init__.py +4 -0
- synkit/Chem/Mapper/solvers/native/assignment.py +99 -0
- synkit/Chem/Mapper/solvers/native/astar.py +22 -0
- synkit/Chem/Mapper/solvers/native/build.py +385 -0
- synkit/Chem/Mapper/solvers/native/classification.py +641 -0
- synkit/Chem/Mapper/solvers/native/core.py +378 -0
- synkit/Chem/Mapper/solvers/native/cpp/CMakeLists.txt +120 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/map_reaction.cpp +29 -0
- synkit/Chem/Mapper/solvers/native/cpp/examples/slap_graph.cpp +63 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/assignment/assignment.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/astar.h +18 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/astar/bound.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/pmcd_witness.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/core/runtime.h +130 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/hydrogen/hydrogen.h +73 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mapper.h +175 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/mces/mces.h +9 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/pabs/seed.h +34 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/reaction/reaction.h +30 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/sepdp/sepdp.h +21 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/slap.h +72 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/solvers/solvers.h +16 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/classification.h +140 -0
- synkit/Chem/Mapper/solvers/native/cpp/include/synkit_mapper/symmetry/cpabs.h +33 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/assignment/abb.cpp +302 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/CMakeLists.txt +12 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/README.md +47 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar.cpp +228 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/astar_graph.cpp +37 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/astar/bound.cpp +212 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/dispatch.cpp +272 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/core/pmcd_witness.cpp +36 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/hydrogen/hydrogen.cpp +380 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/README.md +57 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/mces/mces.cpp +287 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/bridge.cpp +334 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/chemical_floor.inc +181 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/endpoint_symmetry.inc +104 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/exact_helpers.h +20 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_assignment_certificate.h +165 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_certificate.h +125 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_model.h +365 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_provider.inc +319 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_rounding.inc +170 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/lp_test_hooks.h +342 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/objective_reduction.inc +137 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/overlap_dual.inc +351 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/profile_seed.inc +214 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/seed_heuristics.inc +640 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_embedding.cpp +430 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/sparse_root_lp.h +176 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/pabs/test_hooks.inc +262 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/reaction/reaction.cpp +611 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/README.md +61 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/sepdp/sepdp.cpp +253 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/slap.cpp +810 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/formulation.h +138 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/maxsat.cpp +526 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/ortools.cpp +475 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/seed.h +80 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/solvers/weighted_cnf.h +256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/README.md +43 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/dfs.cpp +123 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/supporting/edit_support.cpp +224 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification.cpp +553 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_pipeline.cpp +124 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/classification_stream.h +13 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/cpabs.cpp +455 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/edge_deck.cpp +743 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naugraph.c +732 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.c +94 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naurng.h +49 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.c +1771 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nausparse.h +133 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nautil.c +750 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/naututil.h +355 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.c +1256 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/nauty.h +1544 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.c +1131 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/schreier.h +70 -0
- synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/sorttemplates.c +580 -0
- synkit/Chem/Mapper/solvers/native/hydrogen.py +711 -0
- synkit/Chem/Mapper/solvers/native/implicit.py +506 -0
- synkit/Chem/Mapper/solvers/native/implicit_certificate.py +187 -0
- synkit/Chem/Mapper/solvers/native/implicit_preparation.py +309 -0
- synkit/Chem/Mapper/solvers/native/lib/synkit_mapper.dll +0 -0
- synkit/Chem/Mapper/solvers/native/mces.py +16 -0
- synkit/Chem/Mapper/solvers/native/reaction.py +179 -0
- synkit/Chem/Mapper/solvers/native/reaction_build.py +277 -0
- synkit/Chem/Mapper/solvers/native/reaction_text.py +26 -0
- synkit/Chem/Mapper/solvers/native/runtime.py +242 -0
- synkit/Chem/Mapper/solvers/native/sepdp.py +47 -0
- synkit/Chem/Mapper/solvers/native/slap.py +266 -0
- synkit/Chem/Mapper/solvers/native/solvers.py +67 -0
- synkit/Chem/Mapper/solvers/native/stereo.py +86 -0
- synkit/Chem/Mapper/solvers/native/supporting.py +34 -0
- synkit/Chem/Mapper/solvers/native/symmetry.py +91 -0
- synkit/Chem/Mapper/solvers/slap/__init__.py +29 -0
- synkit/Chem/Mapper/solvers/slap/lap.py +174 -0
- synkit/Chem/Mapper/solvers/slap/sequential.py +696 -0
- synkit/Chem/Mapper/validation/__init__.py +1 -0
- synkit/Chem/Mapper/validation/aam_validator.py +442 -0
- synkit/Chem/Mapper/validation/annotations.py +274 -0
- synkit/Chem/Mapper/validation/bonds.py +124 -0
- synkit/Chem/Mapper/validation/cohorts.py +72 -0
- synkit/Chem/Mapper/validation/identifiability.py +150 -0
- synkit/Chem/Mapper/validation/numerical_scope.py +36 -0
- synkit/Chem/Mapper/validation/orbits.py +137 -0
- synkit/Chem/Molecule/__init__.py +0 -0
- synkit/Chem/Molecule/_chirality_loci.py +165 -0
- synkit/Chem/Molecule/_chirality_types.py +231 -0
- synkit/Chem/Molecule/_helical_loci.py +167 -0
- synkit/Chem/Molecule/_stereo_axis_evidence.py +202 -0
- synkit/Chem/Molecule/_stereo_element_detection.py +193 -0
- synkit/Chem/Molecule/_stereo_orientation_constraints.py +511 -0
- synkit/Chem/Molecule/_tetrahedral_carriers.py +63 -0
- synkit/Chem/Molecule/atom_features.py +379 -0
- synkit/Chem/Molecule/chirality.py +1041 -0
- synkit/Chem/Molecule/cip_assignment.py +569 -0
- synkit/Chem/Molecule/cip_ranking.py +843 -0
- synkit/Chem/Molecule/coordinate_stereo.py +503 -0
- synkit/Chem/Molecule/derived_stereo_naming.py +165 -0
- synkit/Chem/Molecule/descriptors.py +452 -0
- synkit/Chem/Molecule/formula.py +249 -0
- synkit/Chem/Molecule/global_stereo.py +175 -0
- synkit/Chem/Molecule/graph_annotator.py +300 -0
- synkit/Chem/Molecule/standardize.py +817 -0
- synkit/Chem/Molecule/stereo_evidence.py +179 -0
- synkit/Chem/Molecule/stereo_perception.py +1032 -0
- synkit/Chem/Molecule/valence.py +123 -0
- synkit/Chem/Reaction/Mapper/__init__.py +44 -0
- synkit/Chem/Reaction/__init__.py +20 -0
- synkit/Chem/Reaction/aam_validator.py +5 -0
- synkit/Chem/Reaction/balance_check.py +138 -0
- synkit/Chem/Reaction/canon_rsmi.py +249 -0
- synkit/Chem/Reaction/cleaning.py +58 -0
- synkit/Chem/Reaction/deionize.py +199 -0
- synkit/Chem/Reaction/explicit_h_audit.py +232 -0
- synkit/Chem/Reaction/fix_aam.py +64 -0
- synkit/Chem/Reaction/neutralize.py +207 -0
- synkit/Chem/Reaction/radical_wildcard.py +224 -0
- synkit/Chem/Reaction/standardize.py +203 -0
- synkit/Chem/Reaction/tautomerize.py +205 -0
- synkit/Chem/__init__.py +1 -0
- synkit/Chem/utils.py +315 -0
- synkit/Data/__init__.py +0 -0
- synkit/Data/aldol.json.gz +1 -0
- synkit/Data/gen_partial_aam.py +147 -0
- synkit/Data/paracetamol.json.gz +1 -0
- synkit/Graph/Canon/__init__.py +16 -0
- synkit/Graph/Canon/_native/__init__.py +13 -0
- synkit/Graph/Canon/_native/build.py +93 -0
- synkit/Graph/Canon/_native/lib/synkit_canon.dll +0 -0
- synkit/Graph/Canon/_native/prepare.py +49 -0
- synkit/Graph/Canon/_native/runtime.py +140 -0
- synkit/Graph/Canon/_native/search.py +137 -0
- synkit/Graph/Canon/canon_algs.py +228 -0
- synkit/Graph/Canon/canon_graph.py +531 -0
- synkit/Graph/Canon/cpp/CMakeLists.txt +42 -0
- synkit/Graph/Canon/cpp/README.md +123 -0
- synkit/Graph/Canon/cpp/examples/canonical_graph.cpp +16 -0
- synkit/Graph/Canon/cpp/include/synkit_canon/canon.h +85 -0
- synkit/Graph/Canon/cpp/src/canonical.cpp +391 -0
- synkit/Graph/Canon/cpp/src/symmetry.h +83 -0
- synkit/Graph/Canon/cpp/tests/symmetry.cpp +93 -0
- synkit/Graph/Canon/exact.py +1020 -0
- synkit/Graph/Canon/exact_refinement.py +368 -0
- synkit/Graph/Canon/nauty.py +143 -0
- synkit/Graph/Context/__init__.py +0 -0
- synkit/Graph/Context/hier_context.py +244 -0
- synkit/Graph/Context/radius_expand.py +252 -0
- synkit/Graph/FG/__init__.py +19 -0
- synkit/Graph/FG/api.py +39 -0
- synkit/Graph/FG/audit.py +155 -0
- synkit/Graph/FG/catalog.py +919 -0
- synkit/Graph/FG/detector.py +288 -0
- synkit/Graph/FG/model.py +97 -0
- synkit/Graph/FG/recognizers.py +274 -0
- synkit/Graph/FG/ring_system.py +154 -0
- synkit/Graph/Feature/Descriptors/topology.py +857 -0
- synkit/Graph/Feature/Fingerprint/__init__.py +0 -0
- synkit/Graph/Feature/Fingerprint/wl_rxn_fps.py +222 -0
- synkit/Graph/Feature/__init__.py +5 -0
- synkit/Graph/Feature/graph_descriptors.py +323 -0
- synkit/Graph/Feature/graph_fps.py +96 -0
- synkit/Graph/Feature/graph_signature.py +239 -0
- synkit/Graph/Feature/hash_fps.py +133 -0
- synkit/Graph/Feature/morgan_fps.py +88 -0
- synkit/Graph/Feature/path_fps.py +81 -0
- synkit/Graph/Feature/wl_hash.py +134 -0
- synkit/Graph/Fusion/__init__.py +85 -0
- synkit/Graph/Fusion/candidate.py +559 -0
- synkit/Graph/Fusion/constructor.py +877 -0
- synkit/Graph/Fusion/identity.py +184 -0
- synkit/Graph/Fusion/interface.py +700 -0
- synkit/Graph/Fusion/search.py +241 -0
- synkit/Graph/Hyrogen/__init__.py +6 -0
- synkit/Graph/Hyrogen/_misc.py +591 -0
- synkit/Graph/Hyrogen/hcomplete.py +995 -0
- synkit/Graph/Hyrogen/hcomplete_legacy.py +368 -0
- synkit/Graph/Hyrogen/hcompletion_algorithms.py +713 -0
- synkit/Graph/Hyrogen/hextend.py +570 -0
- synkit/Graph/Hyrogen/hextend_legacy.py +215 -0
- synkit/Graph/ITS/__init__.py +4 -0
- synkit/Graph/ITS/its_builder.py +120 -0
- synkit/Graph/ITS/its_construction.py +719 -0
- synkit/Graph/ITS/its_decompose.py +572 -0
- synkit/Graph/ITS/its_destruction.py +331 -0
- synkit/Graph/ITS/its_expand.py +1251 -0
- synkit/Graph/ITS/its_relabel.py +187 -0
- synkit/Graph/ITS/its_reverter.py +356 -0
- synkit/Graph/ITS/normalize_aam.py +145 -0
- synkit/Graph/ITS/partial_its.py +238 -0
- synkit/Graph/ITS/rc_extractor.py +656 -0
- synkit/Graph/ITS/stereo.py +74 -0
- synkit/Graph/MTG/__init__.py +107 -0
- synkit/Graph/MTG/gluing.py +451 -0
- synkit/Graph/MTG/history.py +928 -0
- synkit/Graph/MTG/inventory.py +118 -0
- synkit/Graph/MTG/local.py +447 -0
- synkit/Graph/MTG/mcs_matcher.py +246 -0
- synkit/Graph/MTG/mtg.py +611 -0
- synkit/Graph/MTG/mtg_explore.py +74 -0
- synkit/Graph/MTG/observation.py +209 -0
- synkit/Graph/MTG/process.py +577 -0
- synkit/Graph/MTG/queries.py +66 -0
- synkit/Graph/MTG/realization.py +95 -0
- synkit/Graph/MTG/series_parallel.py +107 -0
- synkit/Graph/MTG/utils.py +424 -0
- synkit/Graph/Matcher/__init__.py +10 -0
- synkit/Graph/Matcher/approx_mcs.py +1264 -0
- synkit/Graph/Matcher/auto_est.py +736 -0
- synkit/Graph/Matcher/automorphism.py +314 -0
- synkit/Graph/Matcher/batch_cluster.py +224 -0
- synkit/Graph/Matcher/dedup_matches.py +247 -0
- synkit/Graph/Matcher/graph_cluster.py +191 -0
- synkit/Graph/Matcher/graph_matcher.py +312 -0
- synkit/Graph/Matcher/graph_morphism.py +421 -0
- synkit/Graph/Matcher/mcs_matcher.py +804 -0
- synkit/Graph/Matcher/multi_turbo_iso.py +186 -0
- synkit/Graph/Matcher/orbit.py +284 -0
- synkit/Graph/Matcher/partial_matcher.py +694 -0
- synkit/Graph/Matcher/sing.py +544 -0
- synkit/Graph/Matcher/subgraph_matcher.py +812 -0
- synkit/Graph/Matcher/turbo_iso.py +272 -0
- synkit/Graph/Matcher/wl_sel.py +537 -0
- synkit/Graph/Mech/__init__.py +26 -0
- synkit/Graph/Mech/conversion.py +1466 -0
- synkit/Graph/Mech/conversion_debug.py +237 -0
- synkit/Graph/Mech/electron_accounting.py +200 -0
- synkit/Graph/Mech/lwg_editor.py +406 -0
- synkit/Graph/Mech/lwg_ops.py +313 -0
- synkit/Graph/Morphism/__init__.py +99 -0
- synkit/Graph/Morphism/constraints.py +460 -0
- synkit/Graph/Morphism/llg.py +999 -0
- synkit/Graph/Morphism/morphism.py +349 -0
- synkit/Graph/Morphism/stereo.py +258 -0
- synkit/Graph/Morphism/stereo_morphism.py +383 -0
- synkit/Graph/Morphism/stereo_morphism_helpers.py +957 -0
- synkit/Graph/Morphism/stereo_morphism_types.py +117 -0
- synkit/Graph/Stereo/__init__.py +376 -0
- synkit/Graph/Stereo/_descriptor_core.py +207 -0
- synkit/Graph/Stereo/_descriptor_serialization.py +138 -0
- synkit/Graph/Stereo/canonical.py +648 -0
- synkit/Graph/Stereo/changes.py +964 -0
- synkit/Graph/Stereo/composition.py +391 -0
- synkit/Graph/Stereo/configured.py +946 -0
- synkit/Graph/Stereo/couplings.py +245 -0
- synkit/Graph/Stereo/descriptors.py +1030 -0
- synkit/Graph/Stereo/enumeration.py +597 -0
- synkit/Graph/Stereo/extended_descriptors.py +406 -0
- synkit/Graph/Stereo/global_configured.py +152 -0
- synkit/Graph/Stereo/global_stereo.py +304 -0
- synkit/Graph/Stereo/identity.py +648 -0
- synkit/Graph/Stereo/interchange.py +496 -0
- synkit/Graph/Stereo/legacy.py +460 -0
- synkit/Graph/Stereo/matching.py +899 -0
- synkit/Graph/Stereo/native.py +154 -0
- synkit/Graph/Stereo/orbits.py +668 -0
- synkit/Graph/Stereo/outcomes.py +99 -0
- synkit/Graph/Stereo/pairwise.py +350 -0
- synkit/Graph/Stereo/rdkit_adapter.py +662 -0
- synkit/Graph/Stereo/rdkit_identity.py +118 -0
- synkit/Graph/Stereo/rdkit_resonance.py +140 -0
- synkit/Graph/Stereo/reaction_interchange.py +266 -0
- synkit/Graph/Stereo/semantics.py +296 -0
- synkit/Graph/Stereo/supports.py +257 -0
- synkit/Graph/Stereo/wire.py +339 -0
- synkit/Graph/Wildcard/__init__.py +0 -0
- synkit/Graph/Wildcard/fuse_graph.py +156 -0
- synkit/Graph/Wildcard/graph_wc.py +303 -0
- synkit/Graph/Wildcard/its_merge.py +857 -0
- synkit/Graph/Wildcard/radwc.py +114 -0
- synkit/Graph/Wildcard/wc_matcher.py +576 -0
- synkit/Graph/Wildcard/wildcard.py +225 -0
- synkit/Graph/__init__.py +17 -0
- synkit/Graph/canon_graph.py +14 -0
- synkit/Graph/syn_graph.py +199 -0
- synkit/Graph/utils.py +324 -0
- synkit/IO/__init__.py +4 -0
- synkit/IO/chem_converter.py +1059 -0
- synkit/IO/combinatorial/__init__.py +8 -0
- synkit/IO/combinatorial/gml_to_graph.py +223 -0
- synkit/IO/combinatorial/graph_to_gml.py +280 -0
- synkit/IO/combinatorial/graph_to_smarts.py +186 -0
- synkit/IO/combinatorial/smarts_expander.py +147 -0
- synkit/IO/combinatorial/smarts_generalizer.py +133 -0
- synkit/IO/combinatorial/smarts_to_graph.py +179 -0
- synkit/IO/conversion.py +42 -0
- synkit/IO/data_io.py +269 -0
- synkit/IO/data_process.py +143 -0
- synkit/IO/debug.py +73 -0
- synkit/IO/gml_to_nx.py +150 -0
- synkit/IO/graph_to_mol.py +199 -0
- synkit/IO/mol_to_graph.py +1105 -0
- synkit/IO/mol_to_graph_chemistry.py +545 -0
- synkit/IO/nx_to_gml.py +209 -0
- synkit/IO/smiles_to_id.py +123 -0
- synkit/Mechanism/__init__.py +151 -0
- synkit/Mechanism/adapters.py +136 -0
- synkit/Mechanism/audit.py +323 -0
- synkit/Mechanism/benchmark.py +638 -0
- synkit/Mechanism/compatibility.py +13 -0
- synkit/Mechanism/drawing.py +85 -0
- synkit/Mechanism/electron_models.py +725 -0
- synkit/Mechanism/equivalence.py +521 -0
- synkit/Mechanism/evidence.py +262 -0
- synkit/Mechanism/interchange.py +141 -0
- synkit/Mechanism/model.py +918 -0
- synkit/Mechanism/neighbor_stereo.py +312 -0
- synkit/Mechanism/radical_data.py +740 -0
- synkit/Mechanism/replay.py +986 -0
- synkit/Mechanism/schema.py +264 -0
- synkit/Mechanism/stereo_state.py +416 -0
- synkit/Mechanism/symbols.py +91 -0
- synkit/Rule/Apply/__init__.py +35 -0
- synkit/Rule/Apply/conditions.py +45 -0
- synkit/Rule/Apply/dpo.py +998 -0
- synkit/Rule/Apply/rule_matcher.py +218 -0
- synkit/Rule/Apply/validation.py +354 -0
- synkit/Rule/Compose/__init__.py +106 -0
- synkit/Rule/Compose/_identity.py +43 -0
- synkit/Rule/Compose/composition.py +976 -0
- synkit/Rule/Compose/laws.py +439 -0
- synkit/Rule/Compose/search.py +771 -0
- synkit/Rule/Compose/synrule.py +170 -0
- synkit/Rule/Modify/__init__.py +0 -0
- synkit/Rule/Modify/implict_rule.py +56 -0
- synkit/Rule/Modify/longest_path.py +92 -0
- synkit/Rule/Modify/molecule_rule.py +115 -0
- synkit/Rule/Modify/prune_templates.py +78 -0
- synkit/Rule/Modify/rule_utils.py +194 -0
- synkit/Rule/Modify/strip_rule.py +97 -0
- synkit/Rule/__init__.py +28 -0
- synkit/Rule/generic_stereo.py +884 -0
- synkit/Rule/stereo_identity.py +271 -0
- synkit/Rule/syn_rule.py +1090 -0
- synkit/Synthesis/MSR/__init__.py +0 -0
- synkit/Synthesis/MSR/path_finder.py +239 -0
- synkit/Synthesis/Metrics/__init__.py +0 -0
- synkit/Synthesis/Metrics/_base.py +52 -0
- synkit/Synthesis/Metrics/_plot.py +129 -0
- synkit/Synthesis/Metrics/_ranking.py +179 -0
- synkit/Synthesis/RBL/__init__.py +80 -0
- synkit/Synthesis/RBL/engine.py +1249 -0
- synkit/Synthesis/RBL/matching.py +652 -0
- synkit/Synthesis/RBL/overlap.py +336 -0
- synkit/Synthesis/RBL/pipeline.py +376 -0
- synkit/Synthesis/RBL/policy.py +139 -0
- synkit/Synthesis/RBL/proof.py +370 -0
- synkit/Synthesis/RBL/reaction.py +506 -0
- synkit/Synthesis/RBL/state.py +169 -0
- synkit/Synthesis/RBL/validation.py +1060 -0
- synkit/Synthesis/Reactor/__init__.py +60 -0
- synkit/Synthesis/Reactor/core/__init__.py +1 -0
- synkit/Synthesis/Reactor/core/engine.py +967 -0
- synkit/Synthesis/Reactor/core/product.py +621 -0
- synkit/Synthesis/Reactor/core/rewrite.py +561 -0
- synkit/Synthesis/Reactor/core/strategy.py +44 -0
- synkit/Synthesis/Reactor/matching/__init__.py +1 -0
- synkit/Synthesis/Reactor/matching/mixin.py +920 -0
- synkit/Synthesis/Reactor/matching/policy.py +345 -0
- synkit/Synthesis/Reactor/matching/symmetry.py +309 -0
- synkit/Synthesis/Reactor/output/__init__.py +1 -0
- synkit/Synthesis/Reactor/output/deduplication.py +703 -0
- synkit/Synthesis/Reactor/output/policy.py +16 -0
- synkit/Synthesis/Reactor/output/serialization.py +485 -0
- synkit/Synthesis/Reactor/output/structural.py +893 -0
- synkit/Synthesis/Reactor/stereo/__init__.py +1 -0
- synkit/Synthesis/Reactor/stereo/assignment.py +35 -0
- synkit/Synthesis/Reactor/stereo/mixin.py +780 -0
- synkit/Synthesis/Reactor/variants/__init__.py +1 -0
- synkit/Synthesis/Reactor/variants/imbalanced.py +180 -0
- synkit/Synthesis/Reactor/variants/partial.py +84 -0
- synkit/Synthesis/Reactor/workflow/__init__.py +1 -0
- synkit/Synthesis/Reactor/workflow/batch.py +550 -0
- synkit/Synthesis/Reactor/workflow/benchmark.py +143 -0
- synkit/Synthesis/Reactor/workflow/postprocess.py +267 -0
- synkit/Synthesis/Reactor/workflow/rule_filter.py +210 -0
- synkit/Synthesis/__init__.py +0 -0
- synkit/Synthesis/reactor_utils.py +316 -0
- synkit/Utils/__init__.py +0 -0
- synkit/Utils/utils.py +172 -0
- synkit/Vis/__init__.py +91 -0
- synkit/Vis/crn/__init__.py +40 -0
- synkit/Vis/epd/__init__.py +20 -0
- synkit/Vis/epd/arrows.py +425 -0
- synkit/Vis/epd/chem.py +197 -0
- synkit/Vis/epd/constants.py +83 -0
- synkit/Vis/epd/layout.py +283 -0
- synkit/Vis/epd/mapping.py +51 -0
- synkit/Vis/epd/models.py +136 -0
- synkit/Vis/epd/render.py +543 -0
- synkit/Vis/epd/utils.py +108 -0
- synkit/Vis/epd/visualizer.py +811 -0
- synkit/Vis/graph_visualizer.py +375 -0
- synkit/Vis/its/__init__.py +19 -0
- synkit/Vis/its/drawer.py +615 -0
- synkit/Vis/its_drawer.py +35 -0
- synkit/Vis/molecule/__init__.py +31 -0
- synkit/Vis/molecule/drawer.py +563 -0
- synkit/Vis/molecule/reaction.py +285 -0
- synkit/Vis/molecule_drawer.py +33 -0
- synkit/Vis/mtg/__init__.py +17 -0
- synkit/Vis/mtg/drawer.py +769 -0
- synkit/Vis/mtg_drawer.py +34 -0
- synkit/Vis/pdf_writer.py +146 -0
- synkit/Vis/reaction/__init__.py +19 -0
- synkit/Vis/reaction/rule.py +141 -0
- synkit/Vis/reaction/rxn.py +532 -0
- synkit/Vis/reaction_drawer.py +41 -0
- synkit/Vis/space/__init__.py +17 -0
- synkit/Vis/space/chemical.py +80 -0
- synkit/Vis/space/embedding.py +87 -0
- synkit/Vis/vis_synedu/Vis/__init__.py +7 -0
- synkit/Vis/vis_synedu/Vis/dpo.py +862 -0
- synkit/Vis/vis_synedu/rxn_vis.py +377 -0
- synkit/Vis/vis_synedu/vis.py +501 -0
- synkit/Vis/visual_drawer.py +215 -0
- synkit/Vis/visual_model.py +520 -0
- synkit/__init__.py +3 -0
- synkit/_native.py +91 -0
- synkit/examples.py +50 -0
- synkit/version.py +23 -0
- synkit-1.6.5.dist-info/METADATA +156 -0
- synkit-1.6.5.dist-info/RECORD +636 -0
- synkit-1.6.5.dist-info/WHEEL +4 -0
- synkit-1.6.5.dist-info/licenses/LICENSE +21 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/COPYRIGHT +44 -0
- synkit-1.6.5.dist-info/licenses/synkit/Chem/Mapper/solvers/native/cpp/src/symmetry/vendor/nauty/LICENSE-2.0.txt +202 -0
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
"""Finite permutation-orbit semantics for local stereochemical frames.
|
|
2
|
+
|
|
3
|
+
The kernel is deliberately independent of descriptor, RDKit, rule, and graph
|
|
4
|
+
objects. A local configuration is an ordered frame modulo the preserving
|
|
5
|
+
permutation group of its shape. Concrete relation witnesses are retained;
|
|
6
|
+
double cosets are invariant classifications, not composable operations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from functools import cached_property, lru_cache
|
|
14
|
+
from itertools import permutations
|
|
15
|
+
from typing import Any, Hashable, Mapping, Sequence
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _stable_key(values: Sequence[Hashable]) -> tuple[tuple[str, str], ...]:
|
|
19
|
+
return tuple((type(value).__name__, repr(value)) for value in values)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True, order=True)
|
|
23
|
+
class Permutation:
|
|
24
|
+
"""A finite position permutation using ``result[i] = source[image[i]]``."""
|
|
25
|
+
|
|
26
|
+
image: tuple[int, ...]
|
|
27
|
+
|
|
28
|
+
def __post_init__(self) -> None:
|
|
29
|
+
object.__setattr__(self, "image", tuple(self.image))
|
|
30
|
+
if tuple(sorted(self.image)) != tuple(range(len(self.image))):
|
|
31
|
+
raise ValueError("A permutation image must be a bijection on 0..n-1.")
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def degree(self) -> int:
|
|
35
|
+
return len(self.image)
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def identity(cls, degree: int) -> "Permutation":
|
|
39
|
+
if degree < 0:
|
|
40
|
+
raise ValueError("Permutation degree must be non-negative.")
|
|
41
|
+
return cls(tuple(range(degree)))
|
|
42
|
+
|
|
43
|
+
def apply(self, values: Sequence[Any]) -> tuple[Any, ...]:
|
|
44
|
+
if len(values) != self.degree:
|
|
45
|
+
raise ValueError("Permutation and frame arities differ.")
|
|
46
|
+
return tuple(values[index] for index in self.image)
|
|
47
|
+
|
|
48
|
+
def then(self, after: "Permutation") -> "Permutation":
|
|
49
|
+
"""Sequence tuple reorderings: ``after.apply(self.apply(values))``.
|
|
50
|
+
|
|
51
|
+
The resulting slot image is ``self ∘ after``. Slot-map composition
|
|
52
|
+
and composition of their tuple-reordering operators have opposite order.
|
|
53
|
+
"""
|
|
54
|
+
if self.degree != after.degree:
|
|
55
|
+
raise ValueError("Only permutations of equal degree compose.")
|
|
56
|
+
return Permutation(tuple(self.image[index] for index in after.image))
|
|
57
|
+
|
|
58
|
+
def inverse(self) -> "Permutation":
|
|
59
|
+
inverse = [0] * self.degree
|
|
60
|
+
for output, source in enumerate(self.image):
|
|
61
|
+
inverse[source] = output
|
|
62
|
+
return Permutation(tuple(inverse))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass(frozen=True)
|
|
66
|
+
class PermutationGroup:
|
|
67
|
+
"""A validated finite permutation group of one fixed degree."""
|
|
68
|
+
|
|
69
|
+
name: str
|
|
70
|
+
degree: int
|
|
71
|
+
elements: tuple[Permutation, ...]
|
|
72
|
+
_closed_by_construction: bool = field(
|
|
73
|
+
default=False,
|
|
74
|
+
repr=False,
|
|
75
|
+
compare=False,
|
|
76
|
+
)
|
|
77
|
+
_symmetric_positions: tuple[int, ...] | None = field(
|
|
78
|
+
default=None,
|
|
79
|
+
repr=False,
|
|
80
|
+
compare=False,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
def __post_init__(self) -> None:
|
|
84
|
+
elements = tuple(sorted(set(self.elements)))
|
|
85
|
+
object.__setattr__(self, "elements", elements)
|
|
86
|
+
if self.degree < 0 or not elements:
|
|
87
|
+
raise ValueError("A finite permutation group must be non-empty.")
|
|
88
|
+
if any(element.degree != self.degree for element in elements):
|
|
89
|
+
raise ValueError("Every group element must have the declared degree.")
|
|
90
|
+
images = {element.image for element in elements}
|
|
91
|
+
identity = Permutation.identity(self.degree)
|
|
92
|
+
if identity.image not in images:
|
|
93
|
+
raise ValueError("A permutation group must contain its identity.")
|
|
94
|
+
if any(element.inverse().image not in images for element in elements):
|
|
95
|
+
raise ValueError("A permutation group must contain every inverse.")
|
|
96
|
+
if not self._closed_by_construction:
|
|
97
|
+
for left in elements:
|
|
98
|
+
for right in elements:
|
|
99
|
+
image = tuple(left.image[index] for index in right.image)
|
|
100
|
+
if image not in images:
|
|
101
|
+
raise ValueError("A permutation group must be closed.")
|
|
102
|
+
|
|
103
|
+
def __contains__(self, value: object) -> bool:
|
|
104
|
+
return isinstance(value, Permutation) and value in self.elements
|
|
105
|
+
|
|
106
|
+
def orbit(self, frame: Sequence[Hashable]) -> tuple[tuple[Hashable, ...], ...]:
|
|
107
|
+
if len(frame) != self.degree:
|
|
108
|
+
raise ValueError("Group and frame arities differ.")
|
|
109
|
+
forms = {element.apply(frame) for element in self.elements}
|
|
110
|
+
return tuple(sorted(forms, key=_stable_key))
|
|
111
|
+
|
|
112
|
+
def canonical(self, frame: Sequence[Hashable]) -> tuple[Hashable, ...]:
|
|
113
|
+
if self._symmetric_positions is not None:
|
|
114
|
+
if len(frame) != self.degree:
|
|
115
|
+
raise ValueError("Group and frame arities differ.")
|
|
116
|
+
canonical = list(frame)
|
|
117
|
+
ordered = sorted(
|
|
118
|
+
(frame[position] for position in self._symmetric_positions),
|
|
119
|
+
key=lambda value: (type(value).__name__, repr(value)),
|
|
120
|
+
)
|
|
121
|
+
for position, value in zip(self._symmetric_positions, ordered):
|
|
122
|
+
canonical[position] = value
|
|
123
|
+
return tuple(canonical)
|
|
124
|
+
return self.orbit(frame)[0]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _lift_permutation(
|
|
128
|
+
degree: int,
|
|
129
|
+
positions: Sequence[int],
|
|
130
|
+
local_image: Sequence[int],
|
|
131
|
+
) -> Permutation:
|
|
132
|
+
image = list(range(degree))
|
|
133
|
+
for output, local_source in enumerate(local_image):
|
|
134
|
+
image[positions[output]] = positions[local_source]
|
|
135
|
+
return Permutation(tuple(image))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _symmetric_group(
|
|
139
|
+
name: str,
|
|
140
|
+
degree: int,
|
|
141
|
+
positions: Sequence[int],
|
|
142
|
+
) -> PermutationGroup:
|
|
143
|
+
elements = tuple(
|
|
144
|
+
_lift_permutation(degree, positions, local_image)
|
|
145
|
+
for local_image in permutations(range(len(positions)))
|
|
146
|
+
)
|
|
147
|
+
# All bijections of a finite position set are closed under composition.
|
|
148
|
+
return PermutationGroup(
|
|
149
|
+
name,
|
|
150
|
+
degree,
|
|
151
|
+
elements,
|
|
152
|
+
_closed_by_construction=True,
|
|
153
|
+
_symmetric_positions=tuple(positions),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _permutation_sign(image: Sequence[int]) -> int:
|
|
158
|
+
inversions = sum(
|
|
159
|
+
image[left] > image[right]
|
|
160
|
+
for left in range(len(image))
|
|
161
|
+
for right in range(left + 1, len(image))
|
|
162
|
+
)
|
|
163
|
+
return -1 if inversions % 2 else 1
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _alternating_group(
|
|
167
|
+
name: str,
|
|
168
|
+
degree: int,
|
|
169
|
+
positions: Sequence[int],
|
|
170
|
+
) -> PermutationGroup:
|
|
171
|
+
elements = tuple(
|
|
172
|
+
_lift_permutation(degree, positions, local_image)
|
|
173
|
+
for local_image in permutations(range(len(positions)))
|
|
174
|
+
if _permutation_sign(local_image) == 1
|
|
175
|
+
)
|
|
176
|
+
# Even permutations are the kernel of the sign homomorphism and are closed.
|
|
177
|
+
return PermutationGroup(name, degree, elements, _closed_by_construction=True)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _group_from_images(
|
|
181
|
+
name: str,
|
|
182
|
+
images: Sequence[Sequence[int]],
|
|
183
|
+
) -> PermutationGroup:
|
|
184
|
+
elements = tuple(Permutation(tuple(image)) for image in images)
|
|
185
|
+
return PermutationGroup(name, len(elements[0].image), elements)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _generated_group(
|
|
189
|
+
name: str,
|
|
190
|
+
degree: int,
|
|
191
|
+
generators: Sequence[Permutation],
|
|
192
|
+
) -> PermutationGroup:
|
|
193
|
+
identity = Permutation.identity(degree)
|
|
194
|
+
discovered = {identity}
|
|
195
|
+
frontier = [identity]
|
|
196
|
+
while frontier:
|
|
197
|
+
current = frontier.pop()
|
|
198
|
+
for generator in generators:
|
|
199
|
+
for candidate in (current.then(generator), generator.then(current)):
|
|
200
|
+
if candidate not in discovered:
|
|
201
|
+
discovered.add(candidate)
|
|
202
|
+
frontier.append(candidate)
|
|
203
|
+
# The fixed-point iteration stops only after the generator closure is complete.
|
|
204
|
+
return PermutationGroup(
|
|
205
|
+
name,
|
|
206
|
+
degree,
|
|
207
|
+
tuple(discovered),
|
|
208
|
+
_closed_by_construction=True,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class StereoSpecification(str, Enum):
|
|
213
|
+
FIXED = "fixed"
|
|
214
|
+
UNSPECIFIED = "unspecified"
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class StereoRelationKind(str, Enum):
|
|
218
|
+
EQUIVALENT = "equivalent"
|
|
219
|
+
OPPOSITE = "opposite"
|
|
220
|
+
RECONFIGURED = "reconfigured"
|
|
221
|
+
UNRELATED = "unrelated"
|
|
222
|
+
UNSPECIFIED = "unspecified"
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@dataclass(frozen=True)
|
|
226
|
+
class ShapeDefinition:
|
|
227
|
+
"""Geometry-specific frame positions and admissible permutation groups."""
|
|
228
|
+
|
|
229
|
+
name: str
|
|
230
|
+
frame_arity: int
|
|
231
|
+
locus_positions: frozenset[int]
|
|
232
|
+
preserving_group: PermutationGroup
|
|
233
|
+
unspecified_group: PermutationGroup
|
|
234
|
+
opposite_permutation: Permutation | None = None
|
|
235
|
+
|
|
236
|
+
def __post_init__(self) -> None:
|
|
237
|
+
object.__setattr__(self, "locus_positions", frozenset(self.locus_positions))
|
|
238
|
+
if self.preserving_group.degree != self.frame_arity:
|
|
239
|
+
raise ValueError("The preserving group has the wrong frame arity.")
|
|
240
|
+
if self.unspecified_group.degree != self.frame_arity:
|
|
241
|
+
raise ValueError("The unspecified group has the wrong frame arity.")
|
|
242
|
+
if not self.locus_positions <= frozenset(range(self.frame_arity)):
|
|
243
|
+
raise ValueError("Locus positions must lie inside the local frame.")
|
|
244
|
+
preserving = set(self.preserving_group.elements)
|
|
245
|
+
unspecified = set(self.unspecified_group.elements)
|
|
246
|
+
if not preserving <= unspecified:
|
|
247
|
+
raise ValueError("The unspecified group must contain the preserving group.")
|
|
248
|
+
if self.opposite_permutation is not None:
|
|
249
|
+
if self.opposite_permutation not in unspecified:
|
|
250
|
+
raise ValueError(
|
|
251
|
+
"An opposite witness must be admissible for the shape."
|
|
252
|
+
)
|
|
253
|
+
if self.opposite_permutation in preserving:
|
|
254
|
+
raise ValueError("An opposite witness cannot preserve configuration.")
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def reference_positions(self) -> tuple[int, ...]:
|
|
258
|
+
return tuple(
|
|
259
|
+
position
|
|
260
|
+
for position in range(self.frame_arity)
|
|
261
|
+
if position not in self.locus_positions
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
def group_for(self, specification: StereoSpecification) -> PermutationGroup:
|
|
265
|
+
return (
|
|
266
|
+
self.preserving_group
|
|
267
|
+
if specification is StereoSpecification.FIXED
|
|
268
|
+
else self.unspecified_group
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@dataclass(frozen=True)
|
|
273
|
+
class PermutationWitness:
|
|
274
|
+
"""A replayable relative permutation between two concrete frames."""
|
|
275
|
+
|
|
276
|
+
shape: str
|
|
277
|
+
permutation: Permutation
|
|
278
|
+
|
|
279
|
+
def apply(self, frame: Sequence[Hashable]) -> tuple[Hashable, ...]:
|
|
280
|
+
return self.permutation.apply(frame)
|
|
281
|
+
|
|
282
|
+
def then(self, after: "PermutationWitness") -> "PermutationWitness":
|
|
283
|
+
if self.shape != after.shape:
|
|
284
|
+
raise ValueError("Stereo witnesses compose only within one shape.")
|
|
285
|
+
return PermutationWitness(
|
|
286
|
+
self.shape,
|
|
287
|
+
self.permutation.then(after.permutation),
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
@dataclass(frozen=True)
|
|
292
|
+
class StereoRelation:
|
|
293
|
+
kind: StereoRelationKind
|
|
294
|
+
shape: str | None
|
|
295
|
+
class_id: tuple[int, ...] | None = None
|
|
296
|
+
witness: PermutationWitness | None = None
|
|
297
|
+
source_canonical: tuple[Hashable, ...] | None = None
|
|
298
|
+
target_canonical: tuple[Hashable, ...] | None = None
|
|
299
|
+
|
|
300
|
+
@property
|
|
301
|
+
def replayable(self) -> bool:
|
|
302
|
+
return self.witness is not None
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@lru_cache(maxsize=None)
|
|
306
|
+
def _cached_double_coset_id(
|
|
307
|
+
shape: str,
|
|
308
|
+
witness_image: tuple[int, ...],
|
|
309
|
+
) -> tuple[int, ...]:
|
|
310
|
+
"""Return ``min(G pi G)`` by direct tuple action, cached per witness."""
|
|
311
|
+
group = SHAPE_DEFINITIONS[shape].preserving_group.elements
|
|
312
|
+
images = {
|
|
313
|
+
tuple(
|
|
314
|
+
left.image[witness_image[right.image[position]]]
|
|
315
|
+
for position in range(len(witness_image))
|
|
316
|
+
)
|
|
317
|
+
for left in group
|
|
318
|
+
for right in group
|
|
319
|
+
}
|
|
320
|
+
return min(images)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
@dataclass(frozen=True, eq=False)
|
|
324
|
+
class StereoConfiguration:
|
|
325
|
+
"""One local frame modulo the fixed or unspecified group of its shape."""
|
|
326
|
+
|
|
327
|
+
shape: str
|
|
328
|
+
frame: tuple[Hashable, ...]
|
|
329
|
+
specification: StereoSpecification = StereoSpecification.FIXED
|
|
330
|
+
|
|
331
|
+
def __post_init__(self) -> None:
|
|
332
|
+
if not isinstance(self.specification, StereoSpecification):
|
|
333
|
+
object.__setattr__(
|
|
334
|
+
self,
|
|
335
|
+
"specification",
|
|
336
|
+
StereoSpecification(self.specification),
|
|
337
|
+
)
|
|
338
|
+
object.__setattr__(self, "frame", tuple(self.frame))
|
|
339
|
+
definition = self.definition
|
|
340
|
+
if len(self.frame) != definition.frame_arity:
|
|
341
|
+
raise ValueError(
|
|
342
|
+
f"Shape {self.shape!r} requires {definition.frame_arity} frame values."
|
|
343
|
+
)
|
|
344
|
+
try:
|
|
345
|
+
unique = len(set(self.frame))
|
|
346
|
+
except TypeError as exc:
|
|
347
|
+
raise TypeError("Stereo frame references must be hashable.") from exc
|
|
348
|
+
if unique != len(self.frame):
|
|
349
|
+
raise ValueError("Stereo frame references must be distinct.")
|
|
350
|
+
|
|
351
|
+
@property
|
|
352
|
+
def definition(self) -> ShapeDefinition:
|
|
353
|
+
try:
|
|
354
|
+
return SHAPE_DEFINITIONS[self.shape]
|
|
355
|
+
except KeyError as exc:
|
|
356
|
+
raise ValueError(f"Unknown stereo shape {self.shape!r}.") from exc
|
|
357
|
+
|
|
358
|
+
@cached_property
|
|
359
|
+
def canonical_frame(self) -> tuple[Hashable, ...]:
|
|
360
|
+
return self.definition.group_for(self.specification).canonical(self.frame)
|
|
361
|
+
|
|
362
|
+
def canonical_form(self) -> tuple[Any, ...]:
|
|
363
|
+
return self.shape, self.specification.value, self.canonical_frame
|
|
364
|
+
|
|
365
|
+
def same_configuration(self, other: object) -> bool:
|
|
366
|
+
return (
|
|
367
|
+
isinstance(other, StereoConfiguration)
|
|
368
|
+
and self.shape == other.shape
|
|
369
|
+
and self.specification is other.specification
|
|
370
|
+
and self.canonical_frame == other.canonical_frame
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
def __eq__(self, other: object) -> bool:
|
|
374
|
+
return self.same_configuration(other)
|
|
375
|
+
|
|
376
|
+
def __hash__(self) -> int:
|
|
377
|
+
return hash(self.canonical_form())
|
|
378
|
+
|
|
379
|
+
def relabel(self, mapping: Mapping[Hashable, Hashable]) -> "StereoConfiguration":
|
|
380
|
+
return StereoConfiguration(
|
|
381
|
+
self.shape,
|
|
382
|
+
tuple(mapping.get(reference, reference) for reference in self.frame),
|
|
383
|
+
self.specification,
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
def replace_reference(
|
|
387
|
+
self,
|
|
388
|
+
old: Hashable,
|
|
389
|
+
new: Hashable,
|
|
390
|
+
) -> "StereoConfiguration":
|
|
391
|
+
return self.replace_references({old: new})
|
|
392
|
+
|
|
393
|
+
def replace_references(
|
|
394
|
+
self,
|
|
395
|
+
replacements: Mapping[Hashable, Hashable],
|
|
396
|
+
) -> "StereoConfiguration":
|
|
397
|
+
unknown = set(replacements) - set(self.frame)
|
|
398
|
+
if unknown:
|
|
399
|
+
raise ValueError(
|
|
400
|
+
f"Replacement sources are absent: {sorted(map(repr, unknown))}."
|
|
401
|
+
)
|
|
402
|
+
protected = {
|
|
403
|
+
self.frame[position] for position in self.definition.locus_positions
|
|
404
|
+
}
|
|
405
|
+
replaced_loci = protected & set(replacements)
|
|
406
|
+
if replaced_loci:
|
|
407
|
+
raise ValueError("Reference replacement cannot replace descriptor loci.")
|
|
408
|
+
return StereoConfiguration(
|
|
409
|
+
self.shape,
|
|
410
|
+
tuple(replacements.get(reference, reference) for reference in self.frame),
|
|
411
|
+
self.specification,
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
def _witness_to(self, other: "StereoConfiguration") -> Permutation | None:
|
|
415
|
+
for permutation in self.definition.unspecified_group.elements:
|
|
416
|
+
if permutation.apply(self.frame) == other.frame:
|
|
417
|
+
return permutation
|
|
418
|
+
return None
|
|
419
|
+
|
|
420
|
+
def _double_coset_id(self, witness: Permutation) -> tuple[int, ...]:
|
|
421
|
+
return _cached_double_coset_id(self.shape, witness.image)
|
|
422
|
+
|
|
423
|
+
def _opposite_class_id(self) -> tuple[int, ...] | None:
|
|
424
|
+
opposite = self.definition.opposite_permutation
|
|
425
|
+
return None if opposite is None else self._double_coset_id(opposite)
|
|
426
|
+
|
|
427
|
+
def relation_to(self, other: object) -> StereoRelation:
|
|
428
|
+
if not isinstance(other, StereoConfiguration) or self.shape != other.shape:
|
|
429
|
+
return StereoRelation(StereoRelationKind.UNRELATED, None)
|
|
430
|
+
witness = self._witness_to(other)
|
|
431
|
+
if witness is None:
|
|
432
|
+
return StereoRelation(
|
|
433
|
+
StereoRelationKind.UNRELATED,
|
|
434
|
+
self.shape,
|
|
435
|
+
source_canonical=self.canonical_frame,
|
|
436
|
+
target_canonical=other.canonical_frame,
|
|
437
|
+
)
|
|
438
|
+
wrapped = PermutationWitness(self.shape, witness)
|
|
439
|
+
if (
|
|
440
|
+
self.specification is StereoSpecification.UNSPECIFIED
|
|
441
|
+
or other.specification is StereoSpecification.UNSPECIFIED
|
|
442
|
+
):
|
|
443
|
+
return StereoRelation(
|
|
444
|
+
StereoRelationKind.UNSPECIFIED,
|
|
445
|
+
self.shape,
|
|
446
|
+
witness=wrapped,
|
|
447
|
+
source_canonical=self.canonical_frame,
|
|
448
|
+
target_canonical=other.canonical_frame,
|
|
449
|
+
)
|
|
450
|
+
class_id = self._double_coset_id(witness)
|
|
451
|
+
if witness in self.definition.preserving_group:
|
|
452
|
+
kind = StereoRelationKind.EQUIVALENT
|
|
453
|
+
elif class_id == self._opposite_class_id():
|
|
454
|
+
kind = StereoRelationKind.OPPOSITE
|
|
455
|
+
else:
|
|
456
|
+
kind = StereoRelationKind.RECONFIGURED
|
|
457
|
+
return StereoRelation(
|
|
458
|
+
kind,
|
|
459
|
+
self.shape,
|
|
460
|
+
class_id,
|
|
461
|
+
wrapped,
|
|
462
|
+
self.canonical_frame,
|
|
463
|
+
other.canonical_frame,
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
def opposite(self) -> "StereoConfiguration":
|
|
467
|
+
opposite = self.definition.opposite_permutation
|
|
468
|
+
if opposite is None:
|
|
469
|
+
raise ValueError(f"Shape {self.shape!r} has no binary opposite operation.")
|
|
470
|
+
if self.specification is StereoSpecification.UNSPECIFIED:
|
|
471
|
+
return self
|
|
472
|
+
return StereoConfiguration(
|
|
473
|
+
self.shape,
|
|
474
|
+
opposite.apply(self.frame),
|
|
475
|
+
self.specification,
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
_TETRA_FIXED = _alternating_group("tetrahedral:A4", 5, (1, 2, 3, 4))
|
|
480
|
+
_TETRA_ALL = _symmetric_group("tetrahedral:S4", 5, (1, 2, 3, 4))
|
|
481
|
+
_TETRA_OPPOSITE = Permutation((0, 2, 1, 3, 4))
|
|
482
|
+
|
|
483
|
+
_SQUARE_FIXED = _group_from_images(
|
|
484
|
+
"square_planar:D4",
|
|
485
|
+
(
|
|
486
|
+
(0, 1, 2, 3, 4),
|
|
487
|
+
(0, 2, 3, 4, 1),
|
|
488
|
+
(0, 3, 4, 1, 2),
|
|
489
|
+
(0, 4, 1, 2, 3),
|
|
490
|
+
(0, 4, 3, 2, 1),
|
|
491
|
+
(0, 3, 2, 1, 4),
|
|
492
|
+
(0, 2, 1, 4, 3),
|
|
493
|
+
(0, 1, 4, 3, 2),
|
|
494
|
+
),
|
|
495
|
+
)
|
|
496
|
+
_SQUARE_ALL = _symmetric_group("square_planar:S4", 5, (1, 2, 3, 4))
|
|
497
|
+
|
|
498
|
+
_TBP_FIXED = _group_from_images(
|
|
499
|
+
"trigonal_bipyramidal:D3",
|
|
500
|
+
(
|
|
501
|
+
(0, 1, 2, 3, 4, 5),
|
|
502
|
+
(0, 1, 2, 5, 3, 4),
|
|
503
|
+
(0, 1, 2, 4, 5, 3),
|
|
504
|
+
(0, 2, 1, 3, 5, 4),
|
|
505
|
+
(0, 2, 1, 5, 4, 3),
|
|
506
|
+
(0, 2, 1, 4, 3, 5),
|
|
507
|
+
),
|
|
508
|
+
)
|
|
509
|
+
_TBP_ALL = _symmetric_group("trigonal_bipyramidal:S5", 6, (1, 2, 3, 4, 5))
|
|
510
|
+
|
|
511
|
+
_OCT_FIXED = _group_from_images(
|
|
512
|
+
"octahedral:O",
|
|
513
|
+
(
|
|
514
|
+
(0, 1, 2, 3, 4, 5, 6),
|
|
515
|
+
(0, 1, 2, 6, 3, 4, 5),
|
|
516
|
+
(0, 1, 2, 5, 6, 3, 4),
|
|
517
|
+
(0, 1, 2, 4, 5, 6, 3),
|
|
518
|
+
(0, 2, 1, 4, 3, 6, 5),
|
|
519
|
+
(0, 2, 1, 5, 4, 3, 6),
|
|
520
|
+
(0, 2, 1, 6, 5, 4, 3),
|
|
521
|
+
(0, 2, 1, 3, 6, 5, 4),
|
|
522
|
+
(0, 3, 5, 2, 4, 1, 6),
|
|
523
|
+
(0, 3, 5, 6, 2, 4, 1),
|
|
524
|
+
(0, 3, 5, 1, 6, 2, 4),
|
|
525
|
+
(0, 3, 5, 4, 1, 6, 2),
|
|
526
|
+
(0, 5, 3, 1, 4, 2, 6),
|
|
527
|
+
(0, 5, 3, 6, 1, 4, 2),
|
|
528
|
+
(0, 5, 3, 2, 6, 1, 4),
|
|
529
|
+
(0, 5, 3, 4, 2, 6, 1),
|
|
530
|
+
(0, 4, 6, 3, 2, 5, 1),
|
|
531
|
+
(0, 4, 6, 1, 3, 2, 5),
|
|
532
|
+
(0, 4, 6, 5, 1, 3, 2),
|
|
533
|
+
(0, 4, 6, 2, 5, 1, 3),
|
|
534
|
+
(0, 6, 4, 3, 1, 5, 2),
|
|
535
|
+
(0, 6, 4, 2, 3, 1, 5),
|
|
536
|
+
(0, 6, 4, 5, 2, 3, 1),
|
|
537
|
+
(0, 6, 4, 1, 5, 2, 3),
|
|
538
|
+
),
|
|
539
|
+
)
|
|
540
|
+
_OCT_ALL = _symmetric_group("octahedral:S6", 7, (1, 2, 3, 4, 5, 6))
|
|
541
|
+
|
|
542
|
+
_PLANAR_BOND_FIXED = _group_from_images(
|
|
543
|
+
"planar_bond:V4",
|
|
544
|
+
(
|
|
545
|
+
(0, 1, 2, 3, 4, 5),
|
|
546
|
+
(1, 0, 2, 3, 5, 4),
|
|
547
|
+
(4, 5, 3, 2, 0, 1),
|
|
548
|
+
(5, 4, 3, 2, 1, 0),
|
|
549
|
+
),
|
|
550
|
+
)
|
|
551
|
+
_PLANAR_BOND_ALL = _generated_group(
|
|
552
|
+
"planar_bond:unknown",
|
|
553
|
+
6,
|
|
554
|
+
(
|
|
555
|
+
Permutation((1, 0, 2, 3, 5, 4)),
|
|
556
|
+
Permutation((4, 5, 3, 2, 0, 1)),
|
|
557
|
+
Permutation((1, 0, 2, 3, 4, 5)),
|
|
558
|
+
),
|
|
559
|
+
)
|
|
560
|
+
_BOND_OPPOSITE = Permutation((1, 0, 2, 3, 4, 5))
|
|
561
|
+
|
|
562
|
+
_ATROP_BOND_FIXED = _group_from_images(
|
|
563
|
+
"atrop_bond:V4",
|
|
564
|
+
(
|
|
565
|
+
(0, 1, 2, 3, 4, 5),
|
|
566
|
+
(1, 0, 2, 3, 5, 4),
|
|
567
|
+
(4, 5, 3, 2, 1, 0),
|
|
568
|
+
(5, 4, 3, 2, 0, 1),
|
|
569
|
+
),
|
|
570
|
+
)
|
|
571
|
+
_ATROP_BOND_ALL = _generated_group(
|
|
572
|
+
"atrop_bond:unknown",
|
|
573
|
+
6,
|
|
574
|
+
(
|
|
575
|
+
Permutation((1, 0, 2, 3, 5, 4)),
|
|
576
|
+
Permutation((4, 5, 3, 2, 1, 0)),
|
|
577
|
+
Permutation((1, 0, 2, 3, 4, 5)),
|
|
578
|
+
),
|
|
579
|
+
)
|
|
580
|
+
|
|
581
|
+
_CUMULENE_AXIS_FIXED = _group_from_images(
|
|
582
|
+
"cumulene_axis:V4",
|
|
583
|
+
tuple(permutation.image for permutation in _ATROP_BOND_FIXED.elements),
|
|
584
|
+
)
|
|
585
|
+
_CUMULENE_AXIS_ALL = _generated_group(
|
|
586
|
+
"cumulene_axis:unknown",
|
|
587
|
+
6,
|
|
588
|
+
(
|
|
589
|
+
Permutation((1, 0, 2, 3, 5, 4)),
|
|
590
|
+
Permutation((4, 5, 3, 2, 1, 0)),
|
|
591
|
+
Permutation((1, 0, 2, 3, 4, 5)),
|
|
592
|
+
),
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
_EXTENDED_CIS_TRANS_FIXED = _group_from_images(
|
|
596
|
+
"extended_cis_trans:V4",
|
|
597
|
+
tuple(permutation.image for permutation in _PLANAR_BOND_FIXED.elements),
|
|
598
|
+
)
|
|
599
|
+
_EXTENDED_CIS_TRANS_ALL = _generated_group(
|
|
600
|
+
"extended_cis_trans:unknown",
|
|
601
|
+
6,
|
|
602
|
+
(
|
|
603
|
+
Permutation((1, 0, 2, 3, 5, 4)),
|
|
604
|
+
Permutation((4, 5, 3, 2, 0, 1)),
|
|
605
|
+
Permutation((1, 0, 2, 3, 4, 5)),
|
|
606
|
+
),
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
SHAPE_DEFINITIONS: Mapping[str, ShapeDefinition] = {
|
|
611
|
+
"tetrahedral": ShapeDefinition(
|
|
612
|
+
"tetrahedral", 5, frozenset({0}), _TETRA_FIXED, _TETRA_ALL, _TETRA_OPPOSITE
|
|
613
|
+
),
|
|
614
|
+
"square_planar": ShapeDefinition(
|
|
615
|
+
"square_planar", 5, frozenset({0}), _SQUARE_FIXED, _SQUARE_ALL
|
|
616
|
+
),
|
|
617
|
+
"trigonal_bipyramidal": ShapeDefinition(
|
|
618
|
+
"trigonal_bipyramidal", 6, frozenset({0}), _TBP_FIXED, _TBP_ALL
|
|
619
|
+
),
|
|
620
|
+
"octahedral": ShapeDefinition(
|
|
621
|
+
"octahedral", 7, frozenset({0}), _OCT_FIXED, _OCT_ALL
|
|
622
|
+
),
|
|
623
|
+
"planar_bond": ShapeDefinition(
|
|
624
|
+
"planar_bond",
|
|
625
|
+
6,
|
|
626
|
+
frozenset({2, 3}),
|
|
627
|
+
_PLANAR_BOND_FIXED,
|
|
628
|
+
_PLANAR_BOND_ALL,
|
|
629
|
+
_BOND_OPPOSITE,
|
|
630
|
+
),
|
|
631
|
+
"atrop_bond": ShapeDefinition(
|
|
632
|
+
"atrop_bond",
|
|
633
|
+
6,
|
|
634
|
+
frozenset({2, 3}),
|
|
635
|
+
_ATROP_BOND_FIXED,
|
|
636
|
+
_ATROP_BOND_ALL,
|
|
637
|
+
_BOND_OPPOSITE,
|
|
638
|
+
),
|
|
639
|
+
"cumulene_axis": ShapeDefinition(
|
|
640
|
+
"cumulene_axis",
|
|
641
|
+
6,
|
|
642
|
+
frozenset({2, 3}),
|
|
643
|
+
_CUMULENE_AXIS_FIXED,
|
|
644
|
+
_CUMULENE_AXIS_ALL,
|
|
645
|
+
_BOND_OPPOSITE,
|
|
646
|
+
),
|
|
647
|
+
"extended_cis_trans": ShapeDefinition(
|
|
648
|
+
"extended_cis_trans",
|
|
649
|
+
6,
|
|
650
|
+
frozenset({2, 3}),
|
|
651
|
+
_EXTENDED_CIS_TRANS_FIXED,
|
|
652
|
+
_EXTENDED_CIS_TRANS_ALL,
|
|
653
|
+
_BOND_OPPOSITE,
|
|
654
|
+
),
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
__all__ = [
|
|
659
|
+
"Permutation",
|
|
660
|
+
"PermutationGroup",
|
|
661
|
+
"PermutationWitness",
|
|
662
|
+
"SHAPE_DEFINITIONS",
|
|
663
|
+
"ShapeDefinition",
|
|
664
|
+
"StereoConfiguration",
|
|
665
|
+
"StereoRelation",
|
|
666
|
+
"StereoRelationKind",
|
|
667
|
+
"StereoSpecification",
|
|
668
|
+
]
|