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,436 @@
|
|
|
1
|
+
"""Minimal non-negative integer semiflows for Petri-net / CRN incidence matrices.
|
|
2
|
+
|
|
3
|
+
A *P-semiflow* is a vector :math:`y \\ge 0` with :math:`y^T S = 0`; a
|
|
4
|
+
*T-semiflow* is a vector :math:`x \\ge 0` with :math:`S x = 0`. Both are
|
|
5
|
+
**non-negative** by definition, so a linear-algebra kernel basis (for example
|
|
6
|
+
one obtained from an SVD) is *not* a semiflow basis: its vectors may be
|
|
7
|
+
negative or mixed-sign, and because any rotation of the kernel is also a valid
|
|
8
|
+
kernel basis, the supports of such vectors are not meaningful.
|
|
9
|
+
|
|
10
|
+
The distinction matters because the standard structural results consume
|
|
11
|
+
*supports of minimal semiflows*, not arbitrary kernel directions. In particular
|
|
12
|
+
the Angeli-De Leenheer-Sontag persistence test asks whether every minimal
|
|
13
|
+
siphon contains the support of some P-semiflow; feeding it kernel vectors makes
|
|
14
|
+
it report false negatives on networks that are provably persistent.
|
|
15
|
+
|
|
16
|
+
This module implements the classical Farkas / Colom-Silva elimination scheme,
|
|
17
|
+
which returns exactly the minimal-support non-negative integer generators of
|
|
18
|
+
the flow cone. All arithmetic is exact (``fractions.Fraction`` internally,
|
|
19
|
+
integers on output), so results do not depend on a floating-point tolerance.
|
|
20
|
+
|
|
21
|
+
.. rubric:: Example
|
|
22
|
+
|
|
23
|
+
.. code-block:: python
|
|
24
|
+
|
|
25
|
+
import numpy as np
|
|
26
|
+
from synkit.CRN.Petrinet.minimal_semiflows import minimal_semiflows
|
|
27
|
+
|
|
28
|
+
# A -> B, C -> D : two independent conservation laws
|
|
29
|
+
S = np.array([[-1, 0], [1, 0], [0, -1], [0, 1]], dtype=float)
|
|
30
|
+
print(minimal_semiflows(S, kind="p"))
|
|
31
|
+
# [[1, 1, 0, 0], [0, 0, 1, 1]]
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
from fractions import Fraction
|
|
37
|
+
from math import gcd
|
|
38
|
+
from typing import Dict, List, Sequence, Set, Tuple
|
|
39
|
+
|
|
40
|
+
import numpy as np
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"minimal_semiflows",
|
|
44
|
+
"SemiflowSearchLimit",
|
|
45
|
+
"minimal_semiflow_supports",
|
|
46
|
+
"is_semiflow",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _normalize_integer_row(row: Sequence[Fraction]) -> List[int]:
|
|
51
|
+
"""Scale an exact rational vector to primitive non-negative integers.
|
|
52
|
+
|
|
53
|
+
The vector is multiplied by the least common multiple of the denominators
|
|
54
|
+
and then divided by the greatest common divisor of the numerators, giving
|
|
55
|
+
the unique primitive integer representative of the ray.
|
|
56
|
+
|
|
57
|
+
:param row:
|
|
58
|
+
Vector of exact rational coefficients.
|
|
59
|
+
:type row: Sequence[Fraction]
|
|
60
|
+
|
|
61
|
+
:return:
|
|
62
|
+
Primitive integer vector.
|
|
63
|
+
:rtype: List[int]
|
|
64
|
+
"""
|
|
65
|
+
denom_lcm = 1
|
|
66
|
+
for value in row:
|
|
67
|
+
d = value.denominator
|
|
68
|
+
denom_lcm = denom_lcm // gcd(denom_lcm, d) * d
|
|
69
|
+
|
|
70
|
+
ints = [int(value * denom_lcm) for value in row]
|
|
71
|
+
|
|
72
|
+
common = 0
|
|
73
|
+
for v in ints:
|
|
74
|
+
common = gcd(common, abs(v))
|
|
75
|
+
if common > 1:
|
|
76
|
+
ints = [v // common for v in ints]
|
|
77
|
+
|
|
78
|
+
return ints
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _support(row: Sequence[Fraction]) -> Set[int]:
|
|
82
|
+
"""Return the index set of non-zero entries.
|
|
83
|
+
|
|
84
|
+
:param row:
|
|
85
|
+
Vector of exact rational coefficients.
|
|
86
|
+
:type row: Sequence[Fraction]
|
|
87
|
+
|
|
88
|
+
:return:
|
|
89
|
+
Indices where the vector is non-zero.
|
|
90
|
+
:rtype: Set[int]
|
|
91
|
+
"""
|
|
92
|
+
return {i for i, v in enumerate(row) if v != 0}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _keep_minimal_support(rows: List[List[Fraction]]) -> List[List[Fraction]]:
|
|
96
|
+
"""Drop vectors whose support strictly contains the support of another.
|
|
97
|
+
|
|
98
|
+
This is the minimality filter of the Farkas algorithm. Only inclusion-
|
|
99
|
+
minimal supports generate extremal rays of the flow cone; every other
|
|
100
|
+
non-negative solution is a non-negative combination of those.
|
|
101
|
+
|
|
102
|
+
:param rows:
|
|
103
|
+
Candidate vectors.
|
|
104
|
+
:type rows: List[List[Fraction]]
|
|
105
|
+
|
|
106
|
+
:return:
|
|
107
|
+
Vectors with inclusion-minimal support, duplicates removed.
|
|
108
|
+
:rtype: List[List[Fraction]]
|
|
109
|
+
"""
|
|
110
|
+
supports = [_support(r) for r in rows]
|
|
111
|
+
keep: List[int] = []
|
|
112
|
+
|
|
113
|
+
for i, si in enumerate(supports):
|
|
114
|
+
if not si:
|
|
115
|
+
continue
|
|
116
|
+
dominated = False
|
|
117
|
+
for j, sj in enumerate(supports):
|
|
118
|
+
if i == j or not sj:
|
|
119
|
+
continue
|
|
120
|
+
# Strict subset, or equal support with a smaller index (dedup).
|
|
121
|
+
if sj < si or (sj == si and j < i):
|
|
122
|
+
dominated = True
|
|
123
|
+
break
|
|
124
|
+
if not dominated:
|
|
125
|
+
keep.append(i)
|
|
126
|
+
|
|
127
|
+
out: List[List[Fraction]] = []
|
|
128
|
+
seen: Set[Tuple[int, ...]] = set()
|
|
129
|
+
for i in keep:
|
|
130
|
+
key = tuple(_normalize_integer_row(rows[i]))
|
|
131
|
+
if key in seen:
|
|
132
|
+
continue
|
|
133
|
+
seen.add(key)
|
|
134
|
+
out.append(rows[i])
|
|
135
|
+
return out
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _farkas(matrix: List[List[Fraction]], n_vars: int) -> List[List[Fraction]]:
|
|
139
|
+
"""Run Farkas elimination for ``{y >= 0 : y @ matrix = 0}``.
|
|
140
|
+
|
|
141
|
+
The tableau starts as ``[I | matrix]``: the left block accumulates the
|
|
142
|
+
coefficients of the generator in terms of the original variables, and the
|
|
143
|
+
right block holds the constraints still to be eliminated. One column of the
|
|
144
|
+
right block is annihilated per iteration by combining every
|
|
145
|
+
positive/negative row pair with non-negative weights, which keeps every row
|
|
146
|
+
non-negative on the left block throughout.
|
|
147
|
+
|
|
148
|
+
:param matrix:
|
|
149
|
+
Constraint matrix with ``n_vars`` rows; column ``k`` is eliminated at
|
|
150
|
+
iteration ``k``.
|
|
151
|
+
:type matrix: List[List[Fraction]]
|
|
152
|
+
|
|
153
|
+
:param n_vars:
|
|
154
|
+
Number of original variables, i.e. the width of the identity block.
|
|
155
|
+
:type n_vars: int
|
|
156
|
+
|
|
157
|
+
:return:
|
|
158
|
+
Minimal non-negative generators, as exact rational vectors of length
|
|
159
|
+
``n_vars``.
|
|
160
|
+
:rtype: List[List[Fraction]]
|
|
161
|
+
"""
|
|
162
|
+
n_cols = len(matrix[0]) if matrix and matrix[0] else 0
|
|
163
|
+
|
|
164
|
+
# tableau row = (generator coefficients, remaining constraint values)
|
|
165
|
+
rows: List[Tuple[List[Fraction], List[Fraction]]] = []
|
|
166
|
+
for i in range(n_vars):
|
|
167
|
+
ident = [Fraction(0)] * n_vars
|
|
168
|
+
ident[i] = Fraction(1)
|
|
169
|
+
rows.append((ident, list(matrix[i])))
|
|
170
|
+
|
|
171
|
+
for col in range(n_cols):
|
|
172
|
+
zero_rows = [r for r in rows if r[1][col] == 0]
|
|
173
|
+
pos_rows = [r for r in rows if r[1][col] > 0]
|
|
174
|
+
neg_rows = [r for r in rows if r[1][col] < 0]
|
|
175
|
+
|
|
176
|
+
combined: List[Tuple[List[Fraction], List[Fraction]]] = list(zero_rows)
|
|
177
|
+
|
|
178
|
+
for p_left, p_right in pos_rows:
|
|
179
|
+
for n_left, n_right in neg_rows:
|
|
180
|
+
a = p_right[col]
|
|
181
|
+
b = -n_right[col]
|
|
182
|
+
# b * positive + a * negative -> entry at `col` becomes 0,
|
|
183
|
+
# and both weights are > 0 so the left block stays >= 0.
|
|
184
|
+
new_left = [b * x + a * y for x, y in zip(p_left, n_left)]
|
|
185
|
+
new_right = [b * x + a * y for x, y in zip(p_right, n_right)]
|
|
186
|
+
if any(v != 0 for v in new_left):
|
|
187
|
+
combined.append((new_left, new_right))
|
|
188
|
+
|
|
189
|
+
if not combined:
|
|
190
|
+
return []
|
|
191
|
+
|
|
192
|
+
# Filter on the generator block: that is where minimality is defined.
|
|
193
|
+
lefts = [left for left, _ in combined]
|
|
194
|
+
kept_lefts = _keep_minimal_support(lefts)
|
|
195
|
+
kept_keys = {tuple(_normalize_integer_row(r)) for r in kept_lefts}
|
|
196
|
+
|
|
197
|
+
deduped: List[Tuple[List[Fraction], List[Fraction]]] = []
|
|
198
|
+
seen: Set[Tuple[int, ...]] = set()
|
|
199
|
+
for left, right in combined:
|
|
200
|
+
key = tuple(_normalize_integer_row(left))
|
|
201
|
+
if key in kept_keys and key not in seen:
|
|
202
|
+
seen.add(key)
|
|
203
|
+
deduped.append((left, right))
|
|
204
|
+
rows = deduped
|
|
205
|
+
|
|
206
|
+
return _keep_minimal_support([left for left, _ in rows])
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class SemiflowSearchLimit(RuntimeError):
|
|
210
|
+
"""A bounded exact search stopped before its answer was complete."""
|
|
211
|
+
|
|
212
|
+
def __init__(self, result):
|
|
213
|
+
self.result = result
|
|
214
|
+
super().__init__(
|
|
215
|
+
f"Semiflow enumeration incomplete: {result.termination_reason}"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _integer_stoichiometry(stoich):
|
|
220
|
+
"""Validate without converting integer input through a lossy float array."""
|
|
221
|
+
s = np.asarray(stoich)
|
|
222
|
+
if s.ndim != 2:
|
|
223
|
+
raise ValueError("stoich must be a 2-dimensional matrix")
|
|
224
|
+
integers = []
|
|
225
|
+
for value in s.flat:
|
|
226
|
+
try:
|
|
227
|
+
integer = int(value)
|
|
228
|
+
except (TypeError, ValueError, OverflowError) as exc:
|
|
229
|
+
raise ValueError("Stoichiometry must contain finite integers") from exc
|
|
230
|
+
if integer != value:
|
|
231
|
+
raise ValueError(
|
|
232
|
+
"Minimal semiflows require an integer stoichiometric matrix"
|
|
233
|
+
)
|
|
234
|
+
if not -(2**63) <= integer < 2**63:
|
|
235
|
+
raise OverflowError(
|
|
236
|
+
"Input stoichiometry exceeds int64; exact conversion refused"
|
|
237
|
+
)
|
|
238
|
+
integers.append(integer)
|
|
239
|
+
return np.asarray(integers, dtype=np.int64).reshape(s.shape)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def minimal_semiflows(
|
|
243
|
+
stoich: np.ndarray,
|
|
244
|
+
*,
|
|
245
|
+
kind: str = "p",
|
|
246
|
+
backend: str = "auto",
|
|
247
|
+
library_path=None,
|
|
248
|
+
**native_options,
|
|
249
|
+
) -> List[List[int]]:
|
|
250
|
+
"""Compute minimal non-negative integer semiflows of a stoichiometric matrix.
|
|
251
|
+
|
|
252
|
+
``stoich`` is the species x reaction net stoichiometric matrix ``S``.
|
|
253
|
+
|
|
254
|
+
- ``kind="p"`` returns minimal ``y >= 0`` with ``y^T S = 0`` (place
|
|
255
|
+
invariants / conservation laws), each of length ``n_species``.
|
|
256
|
+
- ``kind="t"`` returns minimal ``x >= 0`` with ``S x = 0`` (transition
|
|
257
|
+
invariants / steady-state flux modes), each of length ``n_reactions``.
|
|
258
|
+
|
|
259
|
+
Results are exact: coefficients are primitive integers, and each returned
|
|
260
|
+
vector has inclusion-minimal support.
|
|
261
|
+
|
|
262
|
+
:param stoich:
|
|
263
|
+
Net stoichiometric matrix with species as rows and reactions as columns.
|
|
264
|
+
:type stoich: numpy.ndarray
|
|
265
|
+
|
|
266
|
+
:param kind:
|
|
267
|
+
Either ``"p"`` or ``"t"``.
|
|
268
|
+
:type kind: str
|
|
269
|
+
|
|
270
|
+
:return:
|
|
271
|
+
List of minimal semiflows, sorted by support size then lexicographically.
|
|
272
|
+
:rtype: List[List[int]]
|
|
273
|
+
|
|
274
|
+
:raises ValueError:
|
|
275
|
+
If ``stoich`` is not two-dimensional, if it contains non-integer
|
|
276
|
+
entries, or if ``kind`` is not ``"p"`` or ``"t"``.
|
|
277
|
+
|
|
278
|
+
.. rubric:: Example
|
|
279
|
+
|
|
280
|
+
.. code-block:: python
|
|
281
|
+
|
|
282
|
+
import numpy as np
|
|
283
|
+
|
|
284
|
+
# A <-> B
|
|
285
|
+
S = np.array([[-1.0, 1.0], [1.0, -1.0]])
|
|
286
|
+
minimal_semiflows(S, kind="p")
|
|
287
|
+
# [[1, 1]]
|
|
288
|
+
minimal_semiflows(S, kind="t")
|
|
289
|
+
# [[1, 1]]
|
|
290
|
+
"""
|
|
291
|
+
if kind not in {"p", "t"}:
|
|
292
|
+
raise ValueError("kind must be 'p' or 't'")
|
|
293
|
+
|
|
294
|
+
from ..backend import resolve_backend
|
|
295
|
+
|
|
296
|
+
backend, library_path = resolve_backend(backend, library_path)
|
|
297
|
+
if backend not in {"auto", "python", "cpp"}:
|
|
298
|
+
raise ValueError("backend must be 'auto', 'python', or 'cpp'")
|
|
299
|
+
if backend == "cpp" or (backend == "auto" and library_path is not None):
|
|
300
|
+
from ..native import enumerate_semiflows
|
|
301
|
+
|
|
302
|
+
result = enumerate_semiflows(
|
|
303
|
+
stoich, kind=kind, library_path=library_path, **native_options
|
|
304
|
+
)
|
|
305
|
+
if not result.complete:
|
|
306
|
+
raise SemiflowSearchLimit(result)
|
|
307
|
+
return result.value["flows"]
|
|
308
|
+
if native_options:
|
|
309
|
+
raise ValueError(
|
|
310
|
+
"Search budgets require the native backend; use enumerate_semiflows for structured results"
|
|
311
|
+
)
|
|
312
|
+
s_int = _integer_stoichiometry(stoich)
|
|
313
|
+
if not s_int.size:
|
|
314
|
+
return []
|
|
315
|
+
|
|
316
|
+
# Farkas eliminates the columns of `matrix`, so orient it such that the
|
|
317
|
+
# rows are the variables we are solving for.
|
|
318
|
+
matrix_np = s_int if kind == "p" else s_int.T
|
|
319
|
+
n_vars = matrix_np.shape[0]
|
|
320
|
+
from ..Props._rank import full_row_rank_modular
|
|
321
|
+
|
|
322
|
+
if full_row_rank_modular(matrix_np):
|
|
323
|
+
return []
|
|
324
|
+
|
|
325
|
+
matrix = [[Fraction(int(v)) for v in row] for row in matrix_np]
|
|
326
|
+
generators = _farkas(matrix, n_vars)
|
|
327
|
+
|
|
328
|
+
out = [_normalize_integer_row(g) for g in generators]
|
|
329
|
+
out = [g for g in out if any(v != 0 for v in g)]
|
|
330
|
+
out.sort(key=lambda g: (sum(1 for v in g if v != 0), g))
|
|
331
|
+
return out
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def minimal_semiflow_supports(
|
|
335
|
+
stoich: np.ndarray,
|
|
336
|
+
*,
|
|
337
|
+
kind: str = "p",
|
|
338
|
+
labels: Sequence[str] | None = None,
|
|
339
|
+
) -> List[Dict[str, int]]:
|
|
340
|
+
"""Return minimal semiflows as sparse label-to-coefficient mappings.
|
|
341
|
+
|
|
342
|
+
:param stoich:
|
|
343
|
+
Net stoichiometric matrix.
|
|
344
|
+
:type stoich: numpy.ndarray
|
|
345
|
+
|
|
346
|
+
:param kind:
|
|
347
|
+
Either ``"p"`` or ``"t"``.
|
|
348
|
+
:type kind: str
|
|
349
|
+
|
|
350
|
+
:param labels:
|
|
351
|
+
Optional labels for the entries. Defaults to positional indices
|
|
352
|
+
rendered as strings.
|
|
353
|
+
:type labels: Sequence[str] | None
|
|
354
|
+
|
|
355
|
+
:return:
|
|
356
|
+
One sparse mapping per minimal semiflow.
|
|
357
|
+
:rtype: List[Dict[str, int]]
|
|
358
|
+
|
|
359
|
+
:raises ValueError:
|
|
360
|
+
If ``labels`` length does not match the semiflow dimension.
|
|
361
|
+
|
|
362
|
+
.. rubric:: Example
|
|
363
|
+
|
|
364
|
+
.. code-block:: python
|
|
365
|
+
|
|
366
|
+
import numpy as np
|
|
367
|
+
|
|
368
|
+
S = np.array([[-1.0, 1.0], [1.0, -1.0]])
|
|
369
|
+
minimal_semiflow_supports(S, kind="p", labels=["A", "B"])
|
|
370
|
+
# [{'A': 1, 'B': 1}]
|
|
371
|
+
"""
|
|
372
|
+
flows = minimal_semiflows(stoich, kind=kind)
|
|
373
|
+
if not flows:
|
|
374
|
+
return []
|
|
375
|
+
|
|
376
|
+
width = len(flows[0])
|
|
377
|
+
if labels is None:
|
|
378
|
+
names = [str(i) for i in range(width)]
|
|
379
|
+
else:
|
|
380
|
+
names = [str(x) for x in labels]
|
|
381
|
+
if len(names) != width:
|
|
382
|
+
raise ValueError(
|
|
383
|
+
f"labels has length {len(names)}, expected {width} for kind={kind!r}"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
return [{names[i]: int(v) for i, v in enumerate(flow) if v != 0} for flow in flows]
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def is_semiflow(
|
|
390
|
+
stoich: np.ndarray, vector: Sequence[float], *, kind: str = "p"
|
|
391
|
+
) -> bool:
|
|
392
|
+
"""Check whether a vector is a genuine semiflow.
|
|
393
|
+
|
|
394
|
+
A semiflow must be non-negative, non-zero, and in the appropriate kernel.
|
|
395
|
+
This is useful as a test assertion and as a guard on user-supplied vectors.
|
|
396
|
+
|
|
397
|
+
:param stoich:
|
|
398
|
+
Net stoichiometric matrix.
|
|
399
|
+
:type stoich: numpy.ndarray
|
|
400
|
+
|
|
401
|
+
:param vector:
|
|
402
|
+
Candidate vector.
|
|
403
|
+
:type vector: Sequence[float]
|
|
404
|
+
|
|
405
|
+
:param kind:
|
|
406
|
+
Either ``"p"`` or ``"t"``.
|
|
407
|
+
:type kind: str
|
|
408
|
+
|
|
409
|
+
:return:
|
|
410
|
+
``True`` when the vector is a semiflow of the requested kind.
|
|
411
|
+
:rtype: bool
|
|
412
|
+
|
|
413
|
+
:raises ValueError:
|
|
414
|
+
If ``kind`` is not ``"p"`` or ``"t"``.
|
|
415
|
+
|
|
416
|
+
.. rubric:: Example
|
|
417
|
+
|
|
418
|
+
.. code-block:: python
|
|
419
|
+
|
|
420
|
+
import numpy as np
|
|
421
|
+
|
|
422
|
+
S = np.array([[-1.0, 1.0], [1.0, -1.0]])
|
|
423
|
+
is_semiflow(S, [1, 1], kind="p") # True
|
|
424
|
+
is_semiflow(S, [1, -1], kind="p") # False (negative entry)
|
|
425
|
+
"""
|
|
426
|
+
if kind not in {"p", "t"}:
|
|
427
|
+
raise ValueError("kind must be 'p' or 't'")
|
|
428
|
+
|
|
429
|
+
v = np.asarray(vector, dtype=float)
|
|
430
|
+
s = np.asarray(stoich, dtype=float)
|
|
431
|
+
|
|
432
|
+
if v.ndim != 1 or not np.all(v >= -1e-12) or not np.any(np.abs(v) > 1e-12):
|
|
433
|
+
return False
|
|
434
|
+
|
|
435
|
+
residual = v @ s if kind == "p" else s @ v
|
|
436
|
+
return bool(np.allclose(residual, 0.0, atol=1e-9))
|