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,118 @@
|
|
|
1
|
+
"""Exact all-schedule initial stock for a fixed additive event poset.
|
|
2
|
+
|
|
3
|
+
This uses constrained maximum closure, an established minimum-cut reduction.
|
|
4
|
+
Species counts alone do not prove a graph match or a material-copy assignment.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from numbers import Integral
|
|
11
|
+
from typing import Hashable, Mapping
|
|
12
|
+
|
|
13
|
+
import networkx as nx
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class StockWitness:
|
|
18
|
+
"""An enabling ideal attaining a positive initial-stock requirement."""
|
|
19
|
+
|
|
20
|
+
completed_events: frozenset[Hashable]
|
|
21
|
+
next_event: Hashable
|
|
22
|
+
demand: int
|
|
23
|
+
prefix_delta: int
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def required_stock(self) -> int:
|
|
27
|
+
return self.demand - self.prefix_delta
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(frozen=True)
|
|
31
|
+
class StockBound:
|
|
32
|
+
"""Least nonnegative initial stock sufficient for every linear extension.
|
|
33
|
+
|
|
34
|
+
The witness proves the necessity of a positive bound by one reachable
|
|
35
|
+
enabling ideal. It is not a certificate for physical reaction admission.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
initial_stock: int
|
|
39
|
+
witness: StockWitness | None = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _profile(
|
|
43
|
+
graph: nx.DiGraph, values: Mapping[Hashable, int], name: str
|
|
44
|
+
) -> dict[Hashable, int]:
|
|
45
|
+
if set(values) != set(graph):
|
|
46
|
+
raise ValueError(f"{name} must provide exactly one count per event.")
|
|
47
|
+
if any(
|
|
48
|
+
isinstance(value, bool) or not isinstance(value, Integral) or value < 0
|
|
49
|
+
for value in values.values()
|
|
50
|
+
):
|
|
51
|
+
raise ValueError(
|
|
52
|
+
f"{name} counts must be nonnegative integers, excluding booleans."
|
|
53
|
+
)
|
|
54
|
+
return {event: int(values[event]) for event in graph}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _enabling_ideal(
|
|
58
|
+
graph: nx.DiGraph, weights: dict[Hashable, int], event: Hashable
|
|
59
|
+
) -> frozenset[Hashable]:
|
|
60
|
+
source, sink = object(), object()
|
|
61
|
+
network = nx.DiGraph()
|
|
62
|
+
network.add_nodes_from((source, sink, *graph))
|
|
63
|
+
bound = 1 + sum(abs(weight) for weight in weights.values())
|
|
64
|
+
for node, weight in weights.items():
|
|
65
|
+
if weight > 0:
|
|
66
|
+
network.add_edge(source, node, capacity=weight)
|
|
67
|
+
elif weight < 0:
|
|
68
|
+
network.add_edge(node, sink, capacity=-weight)
|
|
69
|
+
for first, second in graph.edges:
|
|
70
|
+
network.add_edge(second, first, capacity=bound)
|
|
71
|
+
for node in nx.ancestors(graph, event):
|
|
72
|
+
network.add_edge(source, node, capacity=bound)
|
|
73
|
+
for node in {event} | nx.descendants(graph, event):
|
|
74
|
+
network.add_edge(node, sink, capacity=bound)
|
|
75
|
+
_, (selected, _) = nx.minimum_cut(network, source, sink)
|
|
76
|
+
return frozenset(set(selected) - {source, sink})
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def minimum_initial_stock(
|
|
80
|
+
event_order: nx.DiGraph,
|
|
81
|
+
demands: Mapping[Hashable, int],
|
|
82
|
+
products: Mapping[Hashable, int],
|
|
83
|
+
) -> StockBound:
|
|
84
|
+
"""Compute exact robust initial stock for one additive resource.
|
|
85
|
+
|
|
86
|
+
At each event its demand must be available before its products are added.
|
|
87
|
+
The returned stock suffices for every linear extension of the supplied
|
|
88
|
+
poset. It need not be minimal for a particular schedule. No schedules or
|
|
89
|
+
ideals are enumerated; at most one minimum-cut solve is needed per event.
|
|
90
|
+
Conditions, graph matches and environment routing require separate checks.
|
|
91
|
+
|
|
92
|
+
:param event_order: Finite simple directed acyclic event graph.
|
|
93
|
+
:param demands: Nonnegative integer input count for every event.
|
|
94
|
+
:param products: Nonnegative integer output count for every event.
|
|
95
|
+
:return: Least robust stock and an attaining enabling ideal when positive.
|
|
96
|
+
:raises ValueError: If the graph or resource profiles violate the contract.
|
|
97
|
+
"""
|
|
98
|
+
if not isinstance(event_order, nx.DiGraph) or event_order.is_multigraph():
|
|
99
|
+
raise ValueError("The event order must be a simple directed graph.")
|
|
100
|
+
graph = event_order.copy()
|
|
101
|
+
if not nx.is_directed_acyclic_graph(graph):
|
|
102
|
+
raise ValueError("The event order must be acyclic; unfold network cycles.")
|
|
103
|
+
inputs = _profile(graph, demands, "Demand")
|
|
104
|
+
outputs = _profile(graph, products, "Product")
|
|
105
|
+
deltas = {event: outputs[event] - inputs[event] for event in graph}
|
|
106
|
+
weights = {event: -deltas[event] for event in graph}
|
|
107
|
+
best = StockBound(0)
|
|
108
|
+
for event in graph:
|
|
109
|
+
ideal = _enabling_ideal(graph, weights, event)
|
|
110
|
+
witness = StockWitness(
|
|
111
|
+
ideal, event, inputs[event], sum(deltas[node] for node in ideal)
|
|
112
|
+
)
|
|
113
|
+
if witness.required_stock > best.initial_stock:
|
|
114
|
+
best = StockBound(witness.required_stock, witness)
|
|
115
|
+
return best
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
__all__ = ["StockBound", "StockWitness", "minimum_initial_stock"]
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
"""Grounded partial-order histories for local edits on fixed atom carriers.
|
|
2
|
+
|
|
3
|
+
This profile derives semantic reads and preservation writes from unguarded,
|
|
4
|
+
atom-preserving source spans. It retains an admitted DPO trace and permits
|
|
5
|
+
shared reads without assigning a whole molecule multiple consumers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from itertools import combinations
|
|
12
|
+
from typing import Any, Hashable, Iterable, Mapping
|
|
13
|
+
|
|
14
|
+
import networkx as nx
|
|
15
|
+
|
|
16
|
+
from synkit.Graph.Morphism import (
|
|
17
|
+
LewisLabelledGraph,
|
|
18
|
+
derive_electron_labeled_graph,
|
|
19
|
+
is_electron_schema,
|
|
20
|
+
)
|
|
21
|
+
from synkit.Rule.Apply import DPOApplication, RuleSpan, SystemBoundary, apply_dpo
|
|
22
|
+
|
|
23
|
+
Coordinate = tuple[str, Hashable, str | None]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LocalHistoryError(ValueError):
|
|
27
|
+
"""Raised when an event or cut is outside the grounded coordinate profile."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(frozen=True)
|
|
31
|
+
class GroundedLocalEvent:
|
|
32
|
+
"""One rule occurrence with its explicit atom match into the fixed world."""
|
|
33
|
+
|
|
34
|
+
event_id: str
|
|
35
|
+
rule: RuleSpan
|
|
36
|
+
match: tuple[tuple[Hashable, Hashable], ...]
|
|
37
|
+
|
|
38
|
+
def __post_init__(self) -> None:
|
|
39
|
+
pairs = self.match.items() if isinstance(self.match, Mapping) else self.match
|
|
40
|
+
object.__setattr__(self, "match", tuple(sorted(pairs, key=repr)))
|
|
41
|
+
if not self.event_id:
|
|
42
|
+
raise LocalHistoryError("A local event requires a nonempty ID.")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(frozen=True)
|
|
46
|
+
class LocalEventRecord:
|
|
47
|
+
"""A retained source execution and its semantic coordinate access sets."""
|
|
48
|
+
|
|
49
|
+
event: GroundedLocalEvent
|
|
50
|
+
reads: frozenset[Coordinate]
|
|
51
|
+
writes: frozenset[Coordinate]
|
|
52
|
+
assignments: tuple[tuple[Coordinate, Any], ...]
|
|
53
|
+
application: DPOApplication
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True)
|
|
57
|
+
class CoordinateCut:
|
|
58
|
+
"""An ideal's decoded world and last-writer versions, without a schedule."""
|
|
59
|
+
|
|
60
|
+
executed_events: frozenset[str]
|
|
61
|
+
world: LewisLabelledGraph
|
|
62
|
+
versions: tuple[tuple[Coordinate, str | None], ...]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _present(pair):
|
|
66
|
+
return "presence", pair, None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _node(node, key):
|
|
70
|
+
return "node", node, key
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _bond(pair, key):
|
|
74
|
+
return "bond", pair, key
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _coordinate_state(world, pairs):
|
|
78
|
+
state = {
|
|
79
|
+
_node(node, key): world.node_labels(node, semantic=True)[key]
|
|
80
|
+
for node in world.node_ids
|
|
81
|
+
for key in world.schema.semantic_node_keys
|
|
82
|
+
}
|
|
83
|
+
for pair in pairs:
|
|
84
|
+
present = pair in world.edge_keys
|
|
85
|
+
state[_present(pair)] = present
|
|
86
|
+
labels = world.edge_labels(pair, semantic=True) if present else {}
|
|
87
|
+
for key in world.schema.semantic_edge_keys:
|
|
88
|
+
# Definedness is tagged independently of the raw value (including None).
|
|
89
|
+
state[_bond(pair, key)] = (True, labels[key]) if present else (False, None)
|
|
90
|
+
return state
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _decode(initial, state, pairs):
|
|
94
|
+
graph = initial.to_networkx()
|
|
95
|
+
graph.remove_edges_from(tuple(graph.edges))
|
|
96
|
+
for node in graph:
|
|
97
|
+
for key in initial.schema.semantic_node_keys:
|
|
98
|
+
graph.nodes[node][key] = state[_node(node, key)]
|
|
99
|
+
for key in initial.schema.node_derived:
|
|
100
|
+
graph.nodes[node].pop(key, None)
|
|
101
|
+
for pair in pairs:
|
|
102
|
+
if state[_present(pair)]:
|
|
103
|
+
labels = {
|
|
104
|
+
key: state[_bond(pair, key)][1]
|
|
105
|
+
for key in initial.schema.semantic_edge_keys
|
|
106
|
+
}
|
|
107
|
+
if any(
|
|
108
|
+
not state[_bond(pair, key)][0]
|
|
109
|
+
for key in initial.schema.semantic_edge_keys
|
|
110
|
+
):
|
|
111
|
+
raise LocalHistoryError("A present bond has an absent coordinate.")
|
|
112
|
+
graph.add_edge(*pair, **labels)
|
|
113
|
+
elif any(
|
|
114
|
+
state[_bond(pair, key)][0] for key in initial.schema.semantic_edge_keys
|
|
115
|
+
):
|
|
116
|
+
raise LocalHistoryError("An absent bond retains a coordinate.")
|
|
117
|
+
if is_electron_schema(initial.schema):
|
|
118
|
+
graph = derive_electron_labeled_graph(graph)
|
|
119
|
+
return LewisLabelledGraph.from_networkx(graph, initial.schema)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _profile(event, initial):
|
|
123
|
+
rule = event.rule
|
|
124
|
+
if rule.left.schema != initial.schema or rule.right.schema != initial.schema:
|
|
125
|
+
raise LocalHistoryError("Every local rule must use the initial world's schema.")
|
|
126
|
+
if rule.condition is not None:
|
|
127
|
+
raise LocalHistoryError("Arbitrary guards have no inferred locality contract.")
|
|
128
|
+
if rule.boundary is SystemBoundary.OPEN:
|
|
129
|
+
raise LocalHistoryError(
|
|
130
|
+
"Open environmental resources require a separate locality contract."
|
|
131
|
+
)
|
|
132
|
+
if rule.left.partial or rule.right.partial or initial.partial:
|
|
133
|
+
raise LocalHistoryError("Local worlds and rule endpoints must be total.")
|
|
134
|
+
if set(rule.left_arm.mapping.values()) != set(rule.left.node_ids) or set(
|
|
135
|
+
rule.right_arm.mapping.values()
|
|
136
|
+
) != set(rule.right.node_ids):
|
|
137
|
+
raise LocalHistoryError(
|
|
138
|
+
"This coordinate profile requires preservation of every rule atom."
|
|
139
|
+
)
|
|
140
|
+
match = dict(event.match)
|
|
141
|
+
if len(match) != len(event.match) or set(match) != set(rule.left.node_ids):
|
|
142
|
+
raise LocalHistoryError(
|
|
143
|
+
"The declared atom match must cover the left pattern exactly."
|
|
144
|
+
)
|
|
145
|
+
if len(set(match.values())) != len(match) or not set(match.values()) <= set(
|
|
146
|
+
initial.node_ids
|
|
147
|
+
):
|
|
148
|
+
raise LocalHistoryError(
|
|
149
|
+
"The declared atom match must be injective into the fixed atom universe."
|
|
150
|
+
)
|
|
151
|
+
return match, {
|
|
152
|
+
rule.right_arm.mapping[interface]: match[left]
|
|
153
|
+
for interface, left in rule.left_arm.mapping.items()
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _access(event, match, right_match, all_coordinates):
|
|
158
|
+
rule = event.rule
|
|
159
|
+
schema = rule.left.schema
|
|
160
|
+
reads = {
|
|
161
|
+
_node(match[node], key)
|
|
162
|
+
for node in rule.left.node_ids
|
|
163
|
+
for key in schema.semantic_node_keys
|
|
164
|
+
}
|
|
165
|
+
if any(
|
|
166
|
+
endpoint.node_labels(node).get("aromatic", False)
|
|
167
|
+
for endpoint in (rule.left, rule.right)
|
|
168
|
+
for node in endpoint.node_ids
|
|
169
|
+
):
|
|
170
|
+
# Phase-aware source matching can inspect more than the local pattern.
|
|
171
|
+
# A whole-world read is sufficient; no extra aromatic concurrency is inferred.
|
|
172
|
+
reads.update(all_coordinates)
|
|
173
|
+
writes = set()
|
|
174
|
+
for interface, left in rule.left_arm.mapping.items():
|
|
175
|
+
retained = rule.interface.node_labels(interface, semantic=True)
|
|
176
|
+
writes.update(
|
|
177
|
+
_node(match[left], key)
|
|
178
|
+
for key in schema.semantic_node_keys
|
|
179
|
+
if key not in retained
|
|
180
|
+
)
|
|
181
|
+
left_edges = {frozenset(match[n] for n in pair) for pair in rule.left.edge_keys}
|
|
182
|
+
right_edges = {
|
|
183
|
+
frozenset(right_match[n] for n in pair) for pair in rule.right.edge_keys
|
|
184
|
+
}
|
|
185
|
+
retained_edges = {
|
|
186
|
+
frozenset(match[rule.left_arm.mapping[n]] for n in pair): pair
|
|
187
|
+
for pair in rule.interface.edge_keys
|
|
188
|
+
}
|
|
189
|
+
for pair in left_edges:
|
|
190
|
+
reads.add(_present(pair))
|
|
191
|
+
reads.update(_bond(pair, key) for key in schema.semantic_edge_keys)
|
|
192
|
+
for pair in right_edges - left_edges:
|
|
193
|
+
# Simple-graph creation requires absence, including every new risk pair.
|
|
194
|
+
reads.add(_present(pair))
|
|
195
|
+
for pair in left_edges | right_edges:
|
|
196
|
+
if pair not in retained_edges:
|
|
197
|
+
writes.add(_present(pair))
|
|
198
|
+
writes.update(_bond(pair, key) for key in schema.semantic_edge_keys)
|
|
199
|
+
else:
|
|
200
|
+
labels = rule.interface.edge_labels(retained_edges[pair], semantic=True)
|
|
201
|
+
writes.update(
|
|
202
|
+
_bond(pair, key)
|
|
203
|
+
for key in schema.semantic_edge_keys
|
|
204
|
+
if key not in labels
|
|
205
|
+
)
|
|
206
|
+
return frozenset(reads), frozenset(writes)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _conflict(first, second):
|
|
210
|
+
return bool(
|
|
211
|
+
first.writes & (second.reads | second.writes)
|
|
212
|
+
or second.writes & (first.reads | first.writes)
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _declared_precedence(events, precedence):
|
|
217
|
+
positions = {event.event_id: index for index, event in enumerate(events)}
|
|
218
|
+
try:
|
|
219
|
+
precedence = tuple(tuple(pair) for pair in precedence)
|
|
220
|
+
valid = all(
|
|
221
|
+
len(pair) == 2
|
|
222
|
+
and pair[0] in positions
|
|
223
|
+
and pair[1] in positions
|
|
224
|
+
and positions[pair[0]] < positions[pair[1]]
|
|
225
|
+
for pair in precedence
|
|
226
|
+
)
|
|
227
|
+
except TypeError:
|
|
228
|
+
valid = False
|
|
229
|
+
if not valid:
|
|
230
|
+
raise LocalHistoryError(
|
|
231
|
+
"Declared precedence must name known events in the supplied trace order."
|
|
232
|
+
)
|
|
233
|
+
return tuple(sorted(set(precedence), key=repr))
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _construct(initial, events, precedence=()):
|
|
237
|
+
if initial.partial:
|
|
238
|
+
raise LocalHistoryError(
|
|
239
|
+
"The initial world must be total, including for an empty trace."
|
|
240
|
+
)
|
|
241
|
+
if is_electron_schema(initial.schema):
|
|
242
|
+
initial = LewisLabelledGraph.from_networkx(
|
|
243
|
+
derive_electron_labeled_graph(initial.to_networkx()), initial.schema
|
|
244
|
+
)
|
|
245
|
+
if len({event.event_id for event in events}) != len(events):
|
|
246
|
+
raise LocalHistoryError("Local event IDs must be distinct.")
|
|
247
|
+
precedence = _declared_precedence(events, precedence)
|
|
248
|
+
plans = tuple((event, *_profile(event, initial)) for event in events)
|
|
249
|
+
pairs = set(initial.edge_keys)
|
|
250
|
+
for event, match, right_match in plans:
|
|
251
|
+
pairs.update(
|
|
252
|
+
frozenset(match[n] for n in pair) for pair in event.rule.left.edge_keys
|
|
253
|
+
)
|
|
254
|
+
pairs.update(
|
|
255
|
+
frozenset(right_match[n] for n in pair)
|
|
256
|
+
for pair in event.rule.right.edge_keys
|
|
257
|
+
)
|
|
258
|
+
pairs = frozenset(pairs)
|
|
259
|
+
world = initial
|
|
260
|
+
records = []
|
|
261
|
+
all_coordinates = frozenset(_coordinate_state(initial, pairs))
|
|
262
|
+
for event, match, right_match in plans:
|
|
263
|
+
reads, writes = _access(event, match, right_match, all_coordinates)
|
|
264
|
+
_require_raw_match(event, world)
|
|
265
|
+
application = apply_dpo(event.rule, world, match)
|
|
266
|
+
if (
|
|
267
|
+
not application.certificate.replay().valid
|
|
268
|
+
or application.result.node_ids != initial.node_ids
|
|
269
|
+
):
|
|
270
|
+
raise LocalHistoryError(
|
|
271
|
+
"The retained source execution does not preserve the fixed atoms."
|
|
272
|
+
)
|
|
273
|
+
before = _coordinate_state(world, pairs)
|
|
274
|
+
after = _coordinate_state(application.result, pairs)
|
|
275
|
+
assignments = tuple(sorted(((key, after[key]) for key in writes), key=repr))
|
|
276
|
+
before.update(assignments)
|
|
277
|
+
if before != after:
|
|
278
|
+
raise LocalHistoryError(
|
|
279
|
+
"The inferred writes do not cover the source execution."
|
|
280
|
+
)
|
|
281
|
+
records.append(LocalEventRecord(event, reads, writes, assignments, application))
|
|
282
|
+
world = application.result
|
|
283
|
+
dependencies = tuple(
|
|
284
|
+
(first.event.event_id, second.event.event_id)
|
|
285
|
+
for first, second in combinations(records, 2)
|
|
286
|
+
if _conflict(first, second)
|
|
287
|
+
)
|
|
288
|
+
dependencies += tuple(pair for pair in precedence if pair not in dependencies)
|
|
289
|
+
return LocalCoordinateHistory(
|
|
290
|
+
initial, tuple(records), pairs, dependencies, precedence
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def _require_raw_match(event, world):
|
|
295
|
+
match = dict(event.match)
|
|
296
|
+
if any(
|
|
297
|
+
event.rule.left.node_labels(node, semantic=True)
|
|
298
|
+
!= world.node_labels(image, semantic=True)
|
|
299
|
+
for node, image in match.items()
|
|
300
|
+
):
|
|
301
|
+
raise LocalHistoryError(
|
|
302
|
+
"The supplied event requires exact raw atom coordinates, not phase equivalence."
|
|
303
|
+
)
|
|
304
|
+
for edge in event.rule.left.edge_keys:
|
|
305
|
+
image = frozenset(match[node] for node in edge)
|
|
306
|
+
if image not in world.edge_keys or (
|
|
307
|
+
event.rule.left.edge_labels(edge, semantic=True)
|
|
308
|
+
!= world.edge_labels(image, semantic=True)
|
|
309
|
+
):
|
|
310
|
+
raise LocalHistoryError(
|
|
311
|
+
"The supplied event requires exact raw bond coordinates, not phase equivalence."
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@dataclass(frozen=True)
|
|
316
|
+
class LocalCoordinateHistory:
|
|
317
|
+
"""A certified trace's coordinate-dependence poset on persistent atom IDs.
|
|
318
|
+
|
|
319
|
+
This is a sufficient trace class, not all possible chemistry or a maximal
|
|
320
|
+
independence inference. Coordinates recreated with equal values remain
|
|
321
|
+
writes because the source interface did not preserve them.
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
initial: LewisLabelledGraph
|
|
325
|
+
records: tuple[LocalEventRecord, ...]
|
|
326
|
+
bond_pairs: frozenset[frozenset[Hashable]]
|
|
327
|
+
causal_pairs: tuple[tuple[str, str], ...]
|
|
328
|
+
declared_precedence: tuple[tuple[str, str], ...] = ()
|
|
329
|
+
|
|
330
|
+
@property
|
|
331
|
+
def causal_graph(self) -> nx.DiGraph:
|
|
332
|
+
"""Return a fresh graph of directed semantic access dependencies."""
|
|
333
|
+
graph = nx.DiGraph()
|
|
334
|
+
graph.add_nodes_from(record.event.event_id for record in self.records)
|
|
335
|
+
graph.add_edges_from(self.causal_pairs)
|
|
336
|
+
return graph
|
|
337
|
+
|
|
338
|
+
def replay(self) -> bool:
|
|
339
|
+
"""Reconstruct the retained trace, accesses, certificates and event order."""
|
|
340
|
+
try:
|
|
341
|
+
fresh = _construct(
|
|
342
|
+
self.initial,
|
|
343
|
+
tuple(record.event for record in self.records),
|
|
344
|
+
self.declared_precedence,
|
|
345
|
+
)
|
|
346
|
+
return fresh == self
|
|
347
|
+
except (ValueError, TypeError, KeyError):
|
|
348
|
+
return False
|
|
349
|
+
|
|
350
|
+
def _configuration_ids(self, completed):
|
|
351
|
+
completed = frozenset(completed)
|
|
352
|
+
graph = self.causal_graph
|
|
353
|
+
if not completed <= set(graph) or any(
|
|
354
|
+
second in completed and first not in completed
|
|
355
|
+
for first, second in graph.edges
|
|
356
|
+
):
|
|
357
|
+
raise LocalHistoryError(
|
|
358
|
+
"A coordinate cut must name a known downward-closed event ideal."
|
|
359
|
+
)
|
|
360
|
+
return completed
|
|
361
|
+
|
|
362
|
+
def configuration(self, completed: Iterable[str]) -> CoordinateCut:
|
|
363
|
+
"""Decode an ideal by last writers without choosing or replaying a schedule.
|
|
364
|
+
|
|
365
|
+
The retained construction is revalidated first. Its cost is separate
|
|
366
|
+
from the coordinate projection, which performs no schedule enumeration.
|
|
367
|
+
|
|
368
|
+
:param completed: IDs of completed events forming an order ideal.
|
|
369
|
+
:return: Anchored world and semantic-coordinate versions at that cut.
|
|
370
|
+
:raises LocalHistoryError: If history replay or ideal validation fails.
|
|
371
|
+
"""
|
|
372
|
+
if not self.replay():
|
|
373
|
+
raise LocalHistoryError(
|
|
374
|
+
"The retained coordinate history is not replayable."
|
|
375
|
+
)
|
|
376
|
+
completed = self._configuration_ids(completed)
|
|
377
|
+
state = _coordinate_state(self.initial, self.bond_pairs)
|
|
378
|
+
versions = {key: None for key in state}
|
|
379
|
+
for record in self.records:
|
|
380
|
+
if record.event.event_id in completed:
|
|
381
|
+
state.update(record.assignments)
|
|
382
|
+
versions.update((key, record.event.event_id) for key in record.writes)
|
|
383
|
+
return CoordinateCut(
|
|
384
|
+
completed,
|
|
385
|
+
_decode(self.initial, state, self.bond_pairs),
|
|
386
|
+
tuple(sorted(versions.items(), key=repr)),
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
def execute(self, order: Iterable[str]) -> tuple[DPOApplication, ...]:
|
|
390
|
+
"""Certify actual primitive source execution in a supplied full extension.
|
|
391
|
+
|
|
392
|
+
:param order: All event IDs once in a topological order.
|
|
393
|
+
:return: Primitive DPO applications on their actual whole-world frames.
|
|
394
|
+
:raises LocalHistoryError: If replay or the declared extension is invalid.
|
|
395
|
+
"""
|
|
396
|
+
if not self.replay():
|
|
397
|
+
raise LocalHistoryError(
|
|
398
|
+
"The retained coordinate history is not replayable."
|
|
399
|
+
)
|
|
400
|
+
order = tuple(order)
|
|
401
|
+
positions = {event: index for index, event in enumerate(order)}
|
|
402
|
+
graph = self.causal_graph
|
|
403
|
+
if (
|
|
404
|
+
len(positions) != len(order)
|
|
405
|
+
or set(order) != set(graph)
|
|
406
|
+
or any(
|
|
407
|
+
positions[first] >= positions[second] for first, second in graph.edges
|
|
408
|
+
)
|
|
409
|
+
):
|
|
410
|
+
raise LocalHistoryError("Execution requires a complete linear extension.")
|
|
411
|
+
by_id = {record.event.event_id: record.event for record in self.records}
|
|
412
|
+
world = self.initial
|
|
413
|
+
applications = []
|
|
414
|
+
for event_id in order:
|
|
415
|
+
event = by_id[event_id]
|
|
416
|
+
_require_raw_match(event, world)
|
|
417
|
+
application = apply_dpo(event.rule, world, dict(event.match))
|
|
418
|
+
if not application.certificate.replay().valid:
|
|
419
|
+
raise LocalHistoryError(
|
|
420
|
+
"A reordered primitive certificate failed replay."
|
|
421
|
+
)
|
|
422
|
+
applications.append(application)
|
|
423
|
+
world = application.result
|
|
424
|
+
return tuple(applications)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def build_local_coordinate_history(
|
|
428
|
+
initial: LewisLabelledGraph,
|
|
429
|
+
events: Iterable[GroundedLocalEvent],
|
|
430
|
+
*,
|
|
431
|
+
precedence: Iterable[tuple[str, str]] = (),
|
|
432
|
+
) -> LocalCoordinateHistory:
|
|
433
|
+
"""Construct a partial-order history from an admitted grounded source trace.
|
|
434
|
+
|
|
435
|
+
All rule atoms are preserved, endpoints/worlds total, guards absent, and
|
|
436
|
+
coordinates raw. Read-only context may be shared. Nonlocal guards, open
|
|
437
|
+
environment state, aromatic phase equivalence and atom allocation are not
|
|
438
|
+
inferred. Aromatic rules conservatively read the complete raw world. This
|
|
439
|
+
is a trace-specific sufficient independence construction.
|
|
440
|
+
|
|
441
|
+
:param initial: Initial total world with persistent atom identities.
|
|
442
|
+
:param events: One admitted sequence with explicit rule matches and IDs.
|
|
443
|
+
:param precedence: Additional declared ordering constraints respected by that sequence.
|
|
444
|
+
:return: Retained primitive certificates and their coordinate-dependence DAG.
|
|
445
|
+
:raises LocalHistoryError: If the declared profile is unsupported or inconsistent.
|
|
446
|
+
"""
|
|
447
|
+
return _construct(initial, tuple(events), tuple(precedence))
|